1 Star 0 Fork 4

huangleiabcde/readWind

forked from 连享会/readWind 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
fastreshape.ado 15.71 KB
一键复制 编辑 原始数据 按行查看 历史
zhbsis 提交于 2019-06-22 19:11 . Add files via upload
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
*===============================================================================
* Program: fastreshape.ado
* Purpose: Quickly reshape datasets in Stata
* Version: 0.2 (2018/01/13)
* Author: Michael Droste
* Website: http://www.github.com/mdroste/stata-fastreshape
*===============================================================================
program define fastreshape
version 13.1
syntax anything, [i(string asis) j(string asis) robust fast string verbose]
*-------------------------------------------------------------------------------
* Setup
*-------------------------------------------------------------------------------
* Preserve dataset in case of failure
preserve
* Parse input
gettoken rtype stubs : anything
*-------------------------------------------------------------------------------
* Exception handling
*-------------------------------------------------------------------------------
* If j not specified and i is, then j should be _j
if "`i'"!="" & "`j'"=="" {
local j _j
}
* Make sure we are either reshaping long or wide
if "`rtype'"!="wide" & "`rtype'"!="long" {
di "Error: Reshape type (`rtype') not wide or long, exiting."
exit 1
}
* Handle implicit syntax
if "`stubs'"=="" & "`i'"=="" & "`j'"=="" {
local m1: char _dta[ReS_stubs]
local m2: char _dta[ReS_i]
local m3: char _dta[ReS_j]
if "`m1'"=="" & "`m2'"=="" & "`m3'"=="" {
di as error "Error: data has not been reshaped yet. The implicit syntax only works if you have reshaped the data in memory already."
exit 1
}
else {
local stubs `m1'
local i `m2'
local j `m3'
}
}
* Make sure i variable exists
if "`i'"!="" {
capture confirm variable `i'
if _rc!=0 {
di as error "Error: i variable (`i') does not exist, exiting."
exit 1
}
}
* If reshape wide, make sure j variable exists
if "`j'"!="" {
if "`rtype'"=="wide" {
capture confirm variable `j'
if _rc!=0 {
di as error "Error: j variable (`j') does not exist, exiting."
exit 1
}
}
}
* If reshape long, make sure j variable does NOT already exist
if "`rtype'"=="long" {
capture confirm variable `j'
if _rc==0 {
di as error "Error: j variable (`j') already exists, exiting."
exit 1
}
}
* If i not specified, exit (unless implicit usage of reshape)
if "`i'"=="" {
di as error "Error: i variable not specified, exiting."
exit 1
}
* If reshape long, make sure i variable uniquely identifies observations
if "`rtype'"=="long" {
tempvar ni
bysort `i': gen `ni' = _n
qui sum `ni'
if r(max)>1 {
di as error "Error: i does not uniquely identify observations, which it should when reshaping long."
exit 1
}
}
* Check type of j, set string option if string
cap confirm string variable `j'
if _rc==0 {
if "`string'"=="" {
di "Warning: the string option was not specified, but the j variable (`j') is a string."
local string "string"
}
}
*-------------------------------------------------------------------------------
* Prep for reshape (long and wide)
*-------------------------------------------------------------------------------
*-------------------------------------------------------------------------------
* Wide reshape
*-------------------------------------------------------------------------------
* If reshape wide...
if "`rtype'"=="wide" {
* Store number of obs and number of vars in long data
local num_obs_long = `=_N'
local num_vars_long = `=c(k)'
* @ functionality for stubs
foreach v in `stubs' {
local c = "`v'"
local wildcard_pos = strpos("`c'","@")
local string_len = strlen("`c'")
if `wildcard_pos'>0 {
* When @ symbol is in the middle of the string
if `wildcard_pos'>1 & `wildcard_pos'<`string_len' {
local c1 = substr("`c'",1,`wildcard_pos'-1) + "*" + substr("`c'",`wildcard_pos'+1,.)
local c2 = substr("`c'",1,`wildcard_pos'-1) + substr("`c'",`wildcard_pos'+1,.) + "*"
local c3 = substr("`c'",1,`wildcard_pos'-1) + substr("`c'",`wildcard_pos'+1,.)
local stubs2 `stubs2' `c3'
}
* When @ symbol is at the end of the string
if `wildcard_pos'==`string_len' {
local c3 = substr("`c'",1,`wildcard_pos'-1)
local stubs2 `stubs2' `c3'
}
* When @ symbol is at the beginning of the string
if `wildcard_pos'==1 {
local c1 = "*" + substr("`c'",`wildcard_pos'+1,.)
local c2 = substr("`c'",`wildcard_pos'+1,.) + "*"
local c3 = substr("`c'",`wildcard_pos'+1,.)
local stubs2 `stubs2' `c3'
}
}
else {
local stubs2 `stubs2' `c'
}
}
local old_stubs `stubs'
local stubs `stubs2'
* Store unique values of j variable (non-string)
if "`verbose'"!="" timer on 1
if "`string'"=="" {
qui tabulate `j', matrow(unique_j)
local num_j = rowsof(unique_j)
forval z=1/`num_j' {
local curr_j = unique_j[`z',1]
local listj `listj' `curr_j'
}
di as text "(note: j = `listj')"
local j1 = unique_j[1,1]
if `num_j'>1 {
local j2 = unique_j[2,1]
if `num_j'>2 {
local j3 = unique_j[`num_j',1]
}
}
}
* Store unique values of j variable (string)
if "`string'"!="" {
qui levelsof `j', local(unique_j)
local num_j = 0
foreach c in `unique_j' {
local num_j = `num_j'+1
local listj `listj' `c'
local unique_j`num_j' "`c'"
}
di as text "(note: j = `listj')"
local j1 "`unique_j1'"
local j2 "`unique_j2'"
local j3 "`unique_j`num_j''"
}
* Store distinct stub variables
foreach v in `stubs' {
capture describe `v', varlist
local stub_vars `stub_vars' `=r(varlist)'
}
if "`verbose'"!="" timer off 1
* XX need to identify all variables in dataset NOT i, j, stub
if "`verbose'"!="" timer on 2
di "stub_vars: `stub_vars' `i' `j'"
qui ds `stub_vars' `i' `j', not
if "`verbose'"!="" timer off 2
* XX make sure the variables above are constant within
* Partition dataset by unique values of j variable
if "`verbose'"!="" timer on 3
forval z=1/`num_j' {
if "`string'"=="" {
local k = unique_j[`z',1]
qui keep if `j'==`k'
}
else {
local k "`unique_j`z''"
qui keep if `j'=="`k'"
}
foreach v in `stubs' {
rename `v' `v'`k'
}
qui drop `j'
tempfile temp_`z'
qui save `temp_`z'', replace
if `z'!=`num_j' {
restore, preserve
}
if `z'==`num_j' {
restore
}
}
if "`verbose'"!="" timer off 3
* Merge partitions together by observation
if "`verbose'"!="" timer on 4
qui use `temp_1', clear
forval k=2/`num_j' {
cap merge 1:1 `i' using `temp_`k'', nogen
if _rc!=0 {
noi di as error "Error: i (`i') not unique within j (`j')."
exit 1
}
}
if "`verbose'"!="" timer off 4
* For wide reshapes, rename @ variables now
foreach v in `old_stubs' {
local c = "`v'"
local wildcard_pos = strpos("`c'","@")
local string_len = strlen("`c'")
if `wildcard_pos'>0 {
* When @ symbol is in the middle of the string
if `wildcard_pos'>1 & `wildcard_pos'<`string_len' {
local c1 = substr("`c'",1,`wildcard_pos'-1) + "*" + substr("`c'",`wildcard_pos'+1,.)
local c2 = substr("`c'",1,`wildcard_pos'-1) + substr("`c'",`wildcard_pos'+1,.) + "*"
local c3 = substr("`c'",1,`wildcard_pos'-1) + substr("`c'",`wildcard_pos'+1,.)
rename `c2' `c1'
}
* When @ symbol is at the end of the string
if `wildcard_pos'==`string_len' {
local c3 = substr("`c'",1,`wildcard_pos'-1)
}
* When @ symbol is at the beginning of the string
if `wildcard_pos'==1 {
local c1 = "*" + substr("`c'",`wildcard_pos'+1,.)
local c2 = substr("`c'",`wildcard_pos'+1,.) + "*"
local c3 = substr("`c'",`wildcard_pos'+1,.)
rename `c2' `c1'
}
}
}
* Format nicely
if "`verbose'"!="" timer on 5
local num_obs_wide = `=_N'
local num_vars_wide = `=c(k)'
if "`verbose'"!="" timer off 6
* Display output
if "`verbose'"!="" timer on 6
di ""
di as text "Data" _col(28) %12s "long" _col(43) "->" _col(48) "wide"
di as text "{hline 78}"
di as text "Number of obs." _col(28) %12s "`num_obs_long'" _col(43) "->" _col(48) "`num_obs_wide'"
di as text "Number of variables" _col(28) %12s "`num_vars_long'" _col(43) "->" _col(48) "`num_vars_wide'"
di as text "j variable (`num_j' values)" _col(28) %12s "`j'" _col(43) "->" _col(48) "(dropped)"
di as text "xij variables:"
foreach v in `stub_vars' {
if `num_j'==3 {
di as text _col(28) %12s "`v'" _col(43) "->" _col(48) "`v'`j1' `v'`j2' `v'`j3'"
}
else if `num_j'==2 {
di as text _col(28) %12s "`v'" _col(43) "->" _col(48) "`v'`j1' `v'`j2'"
}
else if `num_j'==1 {
di as text _col(28) %12s "`v'" _col(43) "->" _col(48) "`v'`j1'"
}
else {
di as text _col(28) %12s "`v'" _col(43) "->" _col(48) "`v'`j1' `v'`j2' ... `v'`j3'"
}
}
di as text "{hline 78}"
if "`verbose'"!="" timer off 6
}
*-------------------------------------------------------------------------------
* Long reshape
* Kudos to http://www.nber.org/stata/efficient/reshape.html
*-------------------------------------------------------------------------------
if "`rtype'"=="long" {
local num_obs_wide = `=_N'
local num_vars_wide = `=c(k)'
* @ functionality for stubs
foreach v in `stubs' {
local c = "`v'"
local wildcard_pos = strpos("`c'","@")
local string_len = strlen("`c'")
di "pos: `wildcard_pos', len: `string_len'"
if `wildcard_pos'>0 {
* When @ symbol is in the middle of the string
if `wildcard_pos'>1 & `wildcard_pos'<`string_len' {
local c1 = substr("`c'",1,`wildcard_pos'-1) + "*" + substr("`c'",`wildcard_pos'+1,.)
local c2 = substr("`c'",1,`wildcard_pos'-1) + substr("`c'",`wildcard_pos'+1,.) + "*"
local c3 = substr("`c'",1,`wildcard_pos'-1) + substr("`c'",`wildcard_pos'+1,.)
rename `c1' `c2'
local stubs2 `stubs2' `c3'
}
* When @ symbol is at the end of the string
if `wildcard_pos'==`string_len' {
local c3 = substr("`c'",1,`wildcard_pos'-1)
local stubs2 `stubs2' `c3'
}
* When @ symbol is at the beginning of the string
if `wildcard_pos'==1 {
di "DING"
local c1 = "*" + substr("`c'",`wildcard_pos'+1,.)
local c2 = substr("`c'",`wildcard_pos'+1,.) + "*"
local c3 = substr("`c'",`wildcard_pos'+1,.)
rename `c1' `c2'
local stubs2 `stubs2' `c3'
}
}
else {
local stubs2 `stubs2' `c'
}
}
local stubs `stubs2'
* Store distinct values of j across all stubs
if "`verbose'"!="" timer on 1
foreach v in `stubs' {
local stub_vars_raw
capture describe `v'*, varlist
if "`=r(varlist)'"!="." {
local stub_vars_raw `stub_vars_raw' `=r(varlist)'
}
foreach v2 in `stub_vars_raw' {
local c = subinstr("`v2'","`v'","",.)
local stub_vars_clean `stub_vars_clean' `c'
}
local all_stubs `all_stubs' `stub_vars_raw'
}
* Store unique values of j variable (non-string)
if "`string'"=="" {
mata: st_matrix("unique_j", uniqrows(strtoreal(tokens(st_local("stub_vars_clean")))'))
local num_j = rowsof(unique_j)
forval z=1/`num_j' {
if "`=unique_j[`z',1]'"!="." {
local list_j `list_j' `=unique_j[`z',1]'
}
}
di as text "(note: j = `list_j')"
}
* Store unique values of j variable (string)
if "`string'"!="" {
mata: unique_j = uniqrows(tokens(st_local("stub_vars_clean")))'
mata: st_local("num_j",strofreal(rows(unique_j)))
gen unique_j = ""
forvalues z=1/`num_j' {
mata: st_local("curr",unique_j[`z',1])
local unique_j`z' = "`curr'" in `z'
}
forval z=1/10 {
if `z'<=`num_j' {
if "`unique_j`z''"!="." {
local list_j `list_j' `unique_j`z''
}
}
}
di as text "(note: j = `list_j')"
}
if "`verbose'"!="" timer off 1
* Identify all variables in dataset NOT i, j, stub
if "`verbose'"!="" timer on 2
if "`string'"=="" qui ds `all_stubs' `i', not
else qui ds `all_stubs' `i' unique_j, not
local non_stubs `r(varlist)'
if "`verbose'"!="" timer off 2
* Write out a separate file for each value of j
if "`verbose'"!="" timer on 3
tempfile tmp_long
qui save `tmp_long'
forval z=1/`num_j' {
if "`string'"=="" local c = unique_j[`z',1]
else local c `unique_j`z''
local allstubs
foreach s in `stubs' {
cap desc `s'`c' using `tmp_long'
if _rc!=0 {
di as text "(note: `s'`c' not found)"
local genlong = 1
}
local allstubs `allstubs' `s'`c'
}
use `i' `allstubs' `non_stubs' using `tmp_long', clear
if "`genlong'"=="1" gen `s'`c' = .
if "`string'"=="" gen `j' = `c'
else gen `j' = "`c'"
rename *`c' *
tempfile temp`z'
qui save `temp`z'', replace
}
if "`verbose'"!="" timer off 3
* Concatenate temp files
if "`verbose'"!="" timer on 4
clear
forval z=1/`num_j' {
append using `temp`z''
}
if "`verbose'"!="" timer off 4
* Format nicely
if "`verbose'"!="" timer on 5
order `i' `j', first
if "`fast'"=="" {
sort `i' `j'
}
local num_obs_long = `=_N'
local num_vars_long = `=c(k)'
if "`verbose'"!="" timer off 5
* Display output
if "`verbose'"!="" timer on 6
di ""
di as text "Data" _col(28) %12s "wide" _col(43) "->" _col(48) "long"
di as text "{hline 78}"
di as text "Number of obs." _col(28) %12s "`num_obs_wide'" _col(43) "->" _col(48) "`num_obs_long'"
di as text "Number of variables" _col(28) %12s "`num_vars_wide'" _col(43) "->" _col(48) "`num_vars_long'"
di as text "j variable (`num_j' values)" _col(43) "->" _col(48) "`j'"
di as text "xij variables:"
foreach v in `stubs' {
if `num_j'==3 {
if "`string'"=="" {
local j1 = unique_j[1,1]
local j2 = unique_j[2,1]
local j3 = unique_j[3,1]
}
else {
local j1 `unique_j1'
local j2 `unique_j2'
local j3 `unique_j3'
}
di as text _col(2) %38s "`v'`j1' `v'`j2' `v'`j3'" _col(43) "->" _col(48) "`v'"
}
else if `num_j'==2 {
if "`string'"=="" {
local j1 = unique_j[1,1]
local j2 = unique_j[2,1]
}
else {
local j1 `unique_j1'
local j2 `unique_j2'
}
di as text _col(2) %38s "`v'`j1' `v'`j2'" _col(43) "->" _col(48) "`v'"
}
else if `num_j'==1 {
if "`string'"=="" {
local j1 = unique_j[1,1]
}
else {
local j1 `unique_j1'
}
di as text _col(2) %38s "`v'`j1'" _col(43) "->" _col(48) "`v'"
}
else {
if "`string'"=="" {
local j1 = unique_j[1,1]
local j2 = unique_j[2,1]
local j3 = unique_j[`num_j',1]
}
else {
local j1 `unique_j1'
local j2 `unique_j2'
local j3 `unique_j`num_j''
}
di as text _col(2) %38s "`v'`j1' `v'`j2' ... `v'`j3'" _col(43) "->" _col(48) "`v'"
}
}
di as text "{hline 78}"
if "`verbose'"!="" timer off 6
}
*-------------------------------------------------------------------------------
* XX optional: return objects
*-------------------------------------------------------------------------------
char _dta[ReS_rtype] `rtype'
char _dta[ReS_stubs] `stubs'
char _dta[ReS_i] `i'
char _dta[ReS_j] `j'
/*
char _dta[ReS_jv] j values, if specified
char _dta[ReS_Xij]
char _dta[ReS_Xij_n] number of X_ij variables
char _dta[ReS_Xij_long#] name of #th X_ij variable in long form
char _dta[ReS_Xij_wide#] name of #th X_ij variable in wide form
char _dta[ReS_Xi] X_i variable names, if specified
char _dta[ReS_atwl] atwl() value, if specified
char _dta[ReS_str] 1 if option string specified; 0 otherwise
*/
if "`verbose'"!="" {
qui timer list
di "Time for stub formatting: `r(t1)'"
di "Time for identifying non-stub, i, j vars: `r(t2)'"
di "Time for writing out files for each j: `r(t3)'"
di "Time for concatenating files: `r(t4)'"
di "Time for formatting: `r(t5)'"
di "Time for printing output: `r(t6)'"
timer clear
}
*-------------------------------------------------------------------------------
* End
*-------------------------------------------------------------------------------
cap restore, not
end
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/huangleiabcde/readWind.git
[email protected]:huangleiabcde/readWind.git
huangleiabcde
readWind
readWind
master

搜索帮助