⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stsplit.ado

📁 是一个经济学管理应用软件 很难找的 但是经济学学生又必须用到
💻 ADO
📖 第 1 页 / 共 2 页
字号:
	}
	drop `ilast'
	compress `firstn' `nrec' `ifirst'
	recast double _t0
	recast double _t

	noi SaveExpand = `nrec' if `touse'

	sort `xid'
	* mark episodes first=1, last=2, inbetween=0
	by `xid' : gen byte `markfl' = 1*(_n==1) + 2*(_n==_N) if `nrec' > 1
	* mark episode with nr of time being split on
	by `xid' : gen long `evid' = `ifirst' + _n - 1
	* all splitted episodes are ended by non-failure, marked -1 for now
	by `xid' : replace _d = -1 if _n < _N & `touse'

	* Update _t0, _t, and the episode marker vname
	* --------------------------------------------

	* use variable T to efficiently implement indexed access to at()
	* sometimes _N may be smaller than -nat- !
	if `nat' > _N {
		* extra cases !
		local extra 1
		local Nplus1 = _N+1
		expand =`nat'-`Nplus1'+2 in l
		replace `touse' = 0 in `Nplus1'/l
	}
	tempvar T
	gen `T' = .
	forv i = 1/`nat' {
		replace `T' = `at`i'' in `i'
	}

	* replace _t0 in all but the first record within xid
	replace _t0 = -`Base'+`T'[`evid'-1] if (`markfl'==0 | `markfl'==2) & `touse'
	* replace _t in all but the last record within xid
	replace _t  = -`Base'+`T'[`evid']   if (`markfl'==0 | `markfl'==1) & `touse'
	* episode marker
	gen `vtype' `vname' = cond(`at1'>0,0,`at1'-1) if `evid'==1 & `touse'
	replace     `vname' = `T'[`evid'-1]           if `evid'!=1 & `touse'
	replace     `vname' = `T'[`nat']              if `evid'>=. & `touse'

	if "`extra'" != "" {
		drop in `Nplus1'/l
	}

	* modify user variables, reset _d
	ModifyUserVars, `codesplit'
	compress _t0 _t `vname'

	* trim (set _st to 0) epsiodes before at_min and after at_max
	* ----

	if "`trim'" != "" {
		local atmin `at1'
		local atmax `at`nat''

		count if float(`vname') < float(`atmin')  & `touse'
		local lb = r(N)
		count if float(`vname') == float(`atmax') & `touse'
		local ub = r(N)

		if `lb' | `ub' {
			replace _st = 0 if float(`vname') < float(`atmin') /*
			  */ | float(`vname') == float(`atmax')
			noi di as txt "(" `lb' " + " `ub' /*
			  */ " obs. trimmed due to lower and upper bounds)"
			if `lb' & `ub' {
				st_note `"`vname'<=`atmin' & `vname'>`atmax' trimmed"'
			}
			else if `lb' {
				st_note `"`vname'<=`atmin' trimmed"'
			}
			else 	st_note `"`vname'>`atmax' trimmed"'
		}
		else {
			noi di as txt "(no obs. trimmed because none out of range)"
		}
	}

	`Done'
} /* quietly */
end

* ============================================================================
* Every -- performs every() episode splitting
* ============================================================================

program define Every
	syntax newvarname(numeric) [=exp] [if] , Every(str) /*
	*/ [ AFter(passthru) COdesplit(passthru) noPREserve Fast ]

	local vname `varlist'
	local vtype `typlist'

quietly {
	tempname e ie it0 it nt xid

	marksample touse, novar
	replace `touse' = 0 if _st == 0

	if `"`exp'`after'"' != "" {
		tempvar Base
		After `Base' `exp' if `touse', `after'
	}
	else	local Base 0

	qui gen `e' = `every' if `touse'
	capt assert !missing(`e') if `touse'
	if _rc {
		noi di as err "every() must be nonmissing"
		exit 498
	}
	capt assert `e' > 0 if `touse'
	if _rc {
		noi di as err "every() must be a strictly positive"
		exit 498
	}

	* in which intervals are _t0 and _t
	* coding: 1 [0,e)  2 [e,2e)  3 [2e,3e) etc
	gen `it0' = 1 + int((_t0+`Base')/`e')       if `touse'
	gen `it'  = 1 + int(((_t+`Base')/`e')-1E-8) if `touse'

	* number of intervals [_t0,_t)
	gen `nt'  = `it'-`it0'+1 if `touse'
	gen `xid' = _n           if `touse'

	* expand!
	if "`preserve'" == "" & "`fast'" == "" {
		preserve
		local Done "restore, not"
	}
	drop `it'
	compress `e' `it0' `nt' `xid'
	recast double _t0
	recast double _t

	noi SaveExpand = `nt' if `touse'

	* adjust key-variables
	sort `xid'
	by `xid' : gen long `ie'= `it0' + _n - 1           if `touse'
	by `xid' : replace _t0  = -`Base' + `e' * (`ie'-1) if _n > 1  & `touse'
	by `xid' : replace _t   = -`Base' + `e' * `ie'     if _n < _N & `touse'
	by `xid' : replace _d   = -1                       if _n < _N & `touse'

	* set episode marker
	gen `vtype' `vname' = 0 if `touse'
	by `xid' : replace `vname' = `e' * (`ie'-1)        if `touse'

	* adjust user variables, reset _d
	ModifyUserVars, `codesplit'

	compress _t0 _t `vname'
	`Done'
} /* quietly */
end

* ===========================================================================
* utility routines
* ===========================================================================

program define After
	syntax newvarname [=/exp] [if] [, AFter(str) ]

	local v `varlist'
	marksample touse, novarlist

	if `"`exp'"' != "" & `"`after'"' != "" {
		di as err "=exp and after() cannot be specified simultaneously"
		exit 198
	}
	else if `"`exp'"' != "" {
		* for backward compatibility with version 1.*.*
		local Exp   `exp'
		local ttime time
		local how   min
	}
	else {
		local 0 `"= `after'"'
		capt syntax =/exp
		if !_rc {
			local Exp   `exp'
			local ttime time
			local how   asis
		}
		else {
			gettoken ttime rest : after , parse("= ")
			if `"`ttime'"' != "time" & `"`ttime'"' != "t" /*
			*/ & `"`ttime'"' != "_t" {
				di as err `"invalid after(): `ttime'"'
				exit 198
			}
			gettoken op fexp : rest , parse("=")
			if "`op'" != "=" {
				di as err "invalid after(): = expected"
				exit 198
			}
			local 0 `"= `fexp'"'
			capt syntax =/exp
			if !_rc {
				local Exp  `exp'
				local how  const
			}
			else {
				gettoken func exp : fexp, parse("(")
				if "`func'" == "asis" | "`func'" == "min" {
					local how `func'
					gettoken Exp rest : exp, parse("(") match(paren)
					if `"`rest'"' != "" | "`paren'" != "(" {
						di as err `"invalid exp in after(): `fexp'"'
						exit 198
					}
				}
				else {
					di as err "invalid after(): asis() or min() expected"
					di as err `"found: `fexp'"'
					exit 198
				}
			}
		}
	}

	*di in re "exp   : `Exp'"
	*di in re "ttime : `ttime'"
	*di in re "how   : `how'"

	* Base will contain the "age" at 0 in analysis t units
	local id `_dta[st_id]'

	sort `touse' `id' _t
	gen double `v' = `Exp' if `touse'

	if "`how'" == "min" {
		* we take earliest value of time/date
		* to avoid sorting, the min is stored in last element
		by `touse' `id' : /*
		*/ replace `v' = `v'[_n-1] if `v'[_n-1]<`v' & `touse'
	}
	else if "`how'" == "const" {
		* verify that base() is constant within id
		capt by `touse' `id' : assert `v' == `v'[1] if `touse'
		if _rc {
			di as err "after() must be constant within `id'"
			exit 198
		}
	}

	if "`ttime'" == "time" {
		local o `_dta[st_o]'
		local s `_dta[st_s]'

	}
	else {
		local o 0
		local s 1
	}
	by `touse' `id' : replace `v' = (`o'-`v'[_N])/`s' if `touse'
	compress `v'
end

* SaveExpand =exp [if] [in]
* wrapper around -expand-, producing message on memory requirement
program define SaveExpand
	syntax =/exp [if] [in]

	marksample touse
	capt expand =`exp' if `touse'
	if _rc {
		tempvar nrec
		quiet gen long `nrec' = cond(`touse', int(`exp'), 1)
		quiet summ `nrec', meanonly
		local nobs = r(sum)

		* compute memory requirement (in kb)
		quiet des, short
		local kb = int((`nobs' * r(width))/1024 + 1)

		di _n as err "impossible to split episodes -- probably too little memory"
		di
		di as txt "expanded dataset would have {res:`nobs'} observations"
		di as txt "memory should be set to at least {res:`kb'} Kb " /*
			*/ "at the current data width"
		di as txt "with extra memory for additional variables"
		exit 950
	}
end

* Created n0
* Reports number of created obs since n0
program define Created
	args n0

	if `n0' != _N {
		local s = cond(_N-`n0'>1, "s", "")
		di as txt "(" =(_N-`n0') " observation`s' (episode`s') created)"
	}
	else {
		di as txt "(no new episodes generated)"
	}
end

* IsVar vname
* returns in s(exist) whether vname is an existing variable
program define IsVar, sclass
	nobreak {
		capture confirm new var `1'
		if _rc {
			capture confirm var `1'
			if _rc == 0 {
				sreturn local exists 1
				exit
			}
		}
	}
	sreturn local exists 0
end

* ModifyUserVars, codesplit(.|#)
* - modifies user variables for _t/_t0 and for event type (failure())
* - recodes -1 to 0 in _d
program define ModifyUserVars
	syntax [, COdesplit(str)]

	IsVar `_dta[st_bt]'
	if `s(exists)' {
		qui replace `_dta[st_bt]'  = _t  * `_dta[st_s]' + `_dta[st_o]' if _st
	}

	IsVar `_dta[st_bt0]'
	if `s(exists)' {
		qui replace `_dta[st_bt0]' = _t0 * `_dta[st_s]' + `_dta[st_o]' if _st
	}

	IsVar `_dta[st_bd]'
	if `s(exists)' {
		if `"`codesplit'"' == "" | `"`codesplit'"' == "." {
			local c .
		}
		else {
			capt confirm number `codesplit'
			if _rc {
				di as err "codesplit() must be a number"
				exit 198
			}
			local c `codesplit'
		}
		qui replace `_dta[st_bd]' = `c' if _d == -1
	}
	qui replace _d = 0 if _d==-1
end

* DropDup newlist : list
* drops all duplicate tokens from list -- copied from hausman.ado
program define DropDup
	args newlist	/*  name of macro to store new list
	*/   colon	   /*  ":"
	*/   list	   /*  list with possible duplicates */

	gettoken token list : list
	while "`token'" != "" {
		local fixlist `fixlist' `token'
		local list : subinstr local list "`token'" "", word all
		gettoken token list : list
	}

	c_local `newlist' `fixlist'
end

* Assert label exp
program define Assert
	gettoken lab 0 : 0
	capt noi assert `0'
	if _rc {
		di as err "assert `lab' failed"
		exit 9
	}
end

exit

History
-------

2.2.0  update using features of Stata 7 (smcl, forvalues); 
       no functional changes

2.1.2  changed the type of various internally used variables from -int- 
       to -long- to fix invalid splitting in large datasets

2.1.0  totally new version by jw/ics
       - added splitting at failure times
       - new implementation of at()
       - added every()
       - more features in after(), replacing the old =exp syntax

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -