/* xtdcce2 auxiliary programs 1. cholqrsolve (mata) 2. cholqrinv (mata) 3. m_xtdcce_inverter (mata) 4. m_xtdcce_solver (mata) 5. xtdcce_PointByPoint (mata) 6.1 xtdcce_m_partialout (mata) 6.2 xtdcce_m_partialout2 (mata) 7. xtdcce_selectindex (mata) 8. xtdcce2_mm_which2 (mata) 9. xtdcce2_m_PutCoeff (mata) 10. xtdcce2_csa 11. xtdcce2_errorcalc 12. xtdcce2_wbsadj 13. issorted 14. xtdcce2_mata2stata */ // Mata utility for sequential use of solvers // Default is cholesky; // if that fails, use QR; // if overridden, use QR. // By Mark Schaffer 2015 capture mata mata drop cholqrsolve() mata: function cholqrsolve ( numeric matrix A, numeric matrix B, | real scalar useqr) { if (args()==2) useqr = 0 real matrix C if (!useqr) { C = cholsolve(A, B) if (C[1,1]==.) { C = qrsolve(A, B) } } else { C = qrsolve(A, B) } return(C) }; end capture mata mata drop cholqrinv() mata: function cholqrinv ( numeric matrix A, | real scalar useqr) { if (args()==2) useqr = 0 real matrix C if (!useqr) { C = cholinv(A) if (C[1,1]==.) { C = qrinv(A) } } else { C = qrinv(A) } return(C) }; end ///Program for matrix inversion. ///Default is cholesky ///if not full rank use invsym (Stata standard) ///and obtain columns to use ///options: ///1. if columns are specified, force use invsym ///2. allow for old method (cholinv, if fails qrinv) ///output ///return: inverse ///indicator for rank (1x2, rank and rows), which method used and variables used capture mata mata drop m_xtdcce_inverter() mata: function m_xtdcce_inverter( numeric matrix A, | real scalar useold, real matrix rank, real matrix coln, string scalar method) { real matrix C if (args() == 1) { useold = 0 coln = 0 } if (args() == 2){ coln = 0 } if (useold == 2) { coln = (1..cols(A)) } if (useold == 1) { C = cholqrinv(A) qrinv(A,rank) method = "cholqr" } else { if (coln[1,1] == 0) { /// calculate rank seperate. if A is not full rank, cholinv still produces results /// 1..cols(A) makes sure variables from left are not dropped C = invsym(A,(1..cols(A))) rank = rows(C)-diag0cnt(C) if (rank < rows(A)) { /// not full rank, use invsym method = "invsym" coln = xtdcce_selectindex(colsum(C:==0):==rows(C):==0) } else { /// full rank use cholsolve C = cholinv(A) method = "chol" } } else { C = invsym(A,coln) rank = rows(C)-diag0cnt(C) method = "invsym" } } rank = (rank, rows(C)) return(C) } end /// same as inverter, rank is for matrix A (which is inverted) capture mata mata drop m_xtdcce_solver() mata: function m_xtdcce_solver( numeric matrix A, numeric matrix B, | real scalar useold, real matrix rank, real matrix coln, string scalar method) { real matrix C real scalar A1 if (args() == 2) { useold = 0 coln = 0 } if (args() < 5){ coln = 0 } if (useold == 2) { coln = (1..cols(A)) } if (useold == 1) { C = cholqrsolve(A,B) qrinv(A,rank) method = "cholqr" rank = (rank, rows(C)) } else { if (coln[1,1] == 0) { /// calculate rank seperate. if A is not full rank, cholsolve still produces results /// 1..cols(A) makes sure variables from left are not dropped A1 = invsym(A,(1..cols(A))) rank = rows(A1)-diag0cnt(A1) if (rank < rows(A)) { /// not full rank, solve by hand C = A1 * B method = "invsym (not full rank)" if (A1[1,1] != 0 & rows(A1)==1 & cols(A1)==1) coln = xtdcce_selectindex(colsum(A1:==0):==rows(A1):==0) } else { /// full rank use cholsolve C = cholsolve(A,B) method = "chol" coln = 0 } } else { /// coln is defined, use invsym on specified columns A1 = invsym(A,coln) C = A1 * B method = "invsym" rank = rows(A1)-diag0cnt(A1) } rank = (rank, rows(A1)) } return(C) } end ***Point by point mata program capture mata mata drop xtdcce_PointByPoint() mata: function xtdcce_PointByPoint(real matrix nrows, real matrix ncols, real matrix expres, real matrix XChange) { p_ncols = ncols p_nrows = nrows p_expres = expres "Point by Point" if (cols(p_ncols) == 1 & cols(p_nrows) > 1) p_ncols = J(1,cols(p_nrows),p_ncols) if (cols(p_ncols) > 1 & cols(p_nrows) == 1) p_nrows = J(1,cols(p_ncols),p_nrows) if (cols(expres) == 1 & rows(expres) == 1& cols(p_nrows) > 1 & cols(p_ncols) > 1) p_expres = J(1,cols(p_nrows),p_expres) for (i=1 ;i <=cols(p_ncols) ; i++) { XChange[p_nrows[i],p_ncols[i]] = p_expres[i] } return(XChange) } end *** Partial Out Program - single cross-section ** quadcross automatically removes missing values and therefore only uses (and updates) entries without missing values ** X1 variable which is partialled out capture mata mata drop xtdcce_m_partialout() mata: function xtdcce_m_partialout ( string scalar X2_n, string scalar X1_n, string scalar touse, real scalar useold, | real scalar rk) { "start partial out" real matrix X1 real matrix X2 st_view(X2,.,tokens(X2_n),touse) st_view(X1,.,tokens(X1_n),touse) X1X1 = quadcross(X1,X1) X1X2 = quadcross(X1,X2) "x1x1 and x1x2 calculated" //Get rank X2[.,.] = (X2 - X1*m_xtdcce_solver(X1X1,X1X2,useold,rk)) "partial out done" "rank condition:" rk } end *** Partial Out Program, loops over all cross-sections. faster than a loop in Stata. ** quadcross automatically removes missing values and therefore only uses (and updates) entries without missing values ** X1 variable which is partialled out ** id_n is the id identifier capture mata mata drop xtdcce_m_partialout2() mata: function xtdcce_m_partialout2 ( string scalar X2_n, string scalar X1_n, string scalar touse, string scalar id_n, real scalar useold, | real scalar rk) { "start partial out" real matrix X1 real matrix X2 real matrix X1_i real matrix X2_i real scalar id st_view(X2,.,tokens(X2_n),touse) st_view(X1,.,tokens(X1_n),touse) rk = 0 id = st_data(.,id_n,touse) ids = uniqrows(id) running = 1 "start loop" while (running<=rows(ids)) { tousei = xtdcce_selectindex(id:==ids[running]) X1_i = X1[tousei,.] X2_i = X2[tousei,.] X1X1 = quadcross(X1_i,X1_i) X1X2 = quadcross(X1_i,X2_i) //Get rank X2[tousei,.] = (X2_i - X1_i*m_xtdcce_solver(X1X1,X1X2,useold,rks=.)) if (rks[1] < rks[2]) { rk = 1 } running++ } } end **Wrapper for selectindex, checks if version is smaller than 13, then runs code, otherwise uses mata function *if `c(version)' < 13 { capture mata mata drop xtdcce_selectindex() mata: function xtdcce_selectindex(a) { row = rows(a) col = cols(a) if (row==1) { output = J(1,0,.) j = 1 while (j<=col) { if (a[1,j] != 0) { output = (output , j) } j++ } } if (col==1) { output = J(0,1,.) j = 1 while (j<=row) { if (a[j,1] != 0) { output = (output \ j) } j++ } } return(output) } end ** xtdcce2_mm_which2 program capture mata mata drop xtdcce2_mm_which2() mata: function xtdcce2_mm_which2(sourceo,searcho,|real scalar exact ) { search = searcho source = sourceo if (eltype(source):=="string") { source = strlower(source) } if (eltype(search):=="string") { search = strlower(search) } sums = 0 for (i=1;i<=length(search);i++) { sums = sums + sum(source:==search[i]) } if (sums > 0) { real matrix output output = J(0,1,.) if (args() == 2) { for (i=1; i<=length(search); i++) { output = (output \ (mm_which(source:==search[i])==J(0,1,.) ? 0 : mm_which(source:==search[i]))) } } if (args() == 3) { if (eltype(search) == "string") { equals = J(0,1,"") } else { equals = J(0,1,.) } if (exact == 1) { for (i=1; i<=length(search); i++) { mm_wh = mm_which(source:==search[i]) if (sum(mm_wh)>0) { equals = (equals \ search[i]) numb = rows(mm_which(equals:==search[i])) mm_wh = mm_wh[numb] } output = (output \ (mm_wh==J(0,1,.) ? 0 : mm_wh)) } } if (exact == 0) { for (i=1; i<=length(search); i++) { mm_wh = xtdcce2_mm_which2(equals,search[i]) if (sum(mm_wh)==0) { equals = (equals \ search[i]) output = (output \ (mm_which(source:==search[i])==J(0,1,.) ? 0 : mm_which(source:==search[i]))) } } } } } else { output = 0 } return(output) } end capture mata mata drop xtdcce2_mm_which2f() mata: function xtdcce2_mm_which2f(source,search ) { real matrix output search_N = rows(search) output = J(search_N,1,0) source_N = rows(source) i = 1 while (i<=search_N) { new_elvec = strlower(source):==strlower(search[i]) if (anyof(new_elvec,1)) { output[i]= xtdcce_selectindex(new_elvec) } i++ } return(output) } end ** program copies coefficients from e(b) matrix into variables capture mata mata drop xtdcce2_m_PutCoeff() mata: function xtdcce2_m_PutCoeff (string scalar VarName, string scalar MatrixName , string scalar idname , string scalar touse , string scalar ColNames) { real scalar ids real scalar output real scalar id id = st_data(.,idname,touse) ids = uniqrows(id) CoeffNames = st_matrixcolstripe(MatrixName)[.,2] CoeffOriginal = st_matrix(MatrixName) ///CoeffNames output = J(rows(id),cols(tokens(VarName)),.) /// bring Coeff Matrix into NxK order K = cols(tokens(VarName)) coeff = J(rows(ids),K,.) c=1 while (c<=K) { namei=tokens(ColNames)[c] namei=namei[1]:+"_":+strofreal(ids) index = xtdcce2_mm_which2(CoeffNames,namei) coeff[.,c] = CoeffOriginal[index]' c++ } /// check that id has same number of vals as y if ((rows(ids) ==rows(coeff)) & (cols(coeff)==cols(tokens(VarName)))) { r = 1 while (r<=rows(ids)) { index = xtdcce_selectindex(id:==ids[r]) output[index,.] = J(rows(index),1,coeff[r,.]) r++ } real scalar X st_view(X,.,VarName,touse) X[.,.] = output } else { output = . } } end ** 10. xtdcce2_csa creates cross-sectional averages ** option numberonly gives only lag number in cross_structure capture program drop xtdcce2_csa program define xtdcce2_csa, rclass syntax varlist(ts) , idvar(varlist) tvar(varlist) cr_lags(numlist) touse(varlist) csa(string) [cluster(varlist) numberonly tousets(varlist) rcceindex rcce(string) hasconstant /// trace /// /// rank condition test rctest /// rctestopt(string) /// ] if "`cr_lags'" == "" { local cr_lags = 0 } if "`tousets'" == "" { local tousets "`touse'" } tsrevar `varlist' local cvarlist `r(varlist)' local c_i = 1 foreach var in `cvarlist' { if "`cluster'" != "" { local clusteri = word("`cluster'",`c_i') if "`clusteri'" == "" { local clusteri `cluster_def' } else { local cluster_def `clusteri' } } local ii `=strtoname("`var'")' tempvar `ii' *by `tvar' `clusteri' `touse' (`idvar'), sort: gen ``ii'' = sum(`var') if `touse' *by `tvar' `clusteri' `touse' (`idvar'), sort: replace ``ii'' = ``ii''[_N] / _N *** keep slow version :/, is using _N, then if statement does not work by `tvar' `clusteri' (`idvar'), sort: egen double ``ii'' = mean(`var') if `touse' *** replace CSA with . if touse == 0 to make sure it is missing replace ``ii'' = . if `touse' == 0 local clist `clist' ``ii'' local c_i = `c_i' + 1 /// get list with correct variables } /// here rc test if "`rctest'" != "" { *noi disp "DO RC TEST" local 0 , `rctestopt' syntax [anything], [er gr REPlications(real 1000) STANDardize(real 5)] local criterion `er' `gr' if "`criterion'" != "" & strlower("`criterion'") != "er" & strlower("`criterion'") != "gr" { noi disp "Criterion invalid. Set to GR." local criterion GR } else if wordcount("`criterion'") > 1 { noi disp "Criterion invalid. Set to GR." local criterion GR } if strlower("`criterion'") == "er" local criterion 1 else local criterion 2 tempvar W gen `W' = rnormal(0,1) by `tvar', sort: replace `W' = `W'[1] sort `idvar' `tvar' tempname rctest_results mata xtdcce2_rctest("`cvarlist'","`clist'","`W'","`touse'","`idvar' `tvar'",`criterion',`replications',`standardize',("`trace'"!=""),"`rctest_results'") } local i = 1 local lagidef = 0 foreach var in `clist' { local lagi = word("`cr_lags'",`i') if "`lagi'" == "" { local lagi = `lagidef' } else { local lagidef = `lagi' } sort `idvar' `tvar' tsrevar L(0/`lagi').`var' local clistfull `clistfull' `r(varlist)' tempname touse2 gen `touse2' = 1 if `tousets' foreach var in `r(varlist)' { replace `var' = `var' * `touse2' } drop `touse2' if "`cluster'" != "" { local clusteri = word("`cluster'",`c_i') if "`clusteri'" == "" { local clusteri `cluster_def' } else { local cluster_def `clusteri' } if "`numberonly'" == "" { local cross_structure "`cross_structure' `=word("`cvarlist'",`i')'(`lagi'; `clusteri')" } else { local cross_structure "`cross_structure' `lagi'" } } else { if "`numberonly'" == "" { local cross_structure "`cross_structure' `=word("`cvarlist'",`i')'(`lagi')" } else { local cross_structure "`cross_structure' `lagi'" } } local i = `i' + 1 } local i = 1 foreach var in `clistfull' { *rename `var' `csa'_`i' gen double `csa'_`i' = `var' drop `var' local clistn `clistn' `csa'_`i' local i = `i' + 1 } if "`rcce'`rcceindex'" != "" { /// clistfull needs to be Fhat /// add option to select the criterion /// add check that xtnumfac is required tempname numfac if "`rcceindex'" != "" & "`rcce'" == "" { local rcce criterion("ER") } local 0 , `rcce' syntax [anything], [Criterion(string) npc(real 0) SCale] if "`criterion'"!= "" & `npc' > 0 { disp "rcce(criterion()) and rcce(npc()) cannot be combined. npc(`npc') ignored" local npc 0 } if "`criterion'" == "" & `npc' == 0 local criterion "ER" if "`criterion'" == "none" local criterion "" if "`criterion'" != "" { local criterion = strlower("`criterion'") /*foreach nname in pc1 pc2 pc3 ic1 ic2 ic3 er gr gos ed { if "`nname'" == "`criterion'" local crit = `s' local s = `s' + 1 }*/ if "`criterion'" == "er" local crit = 1 else local crit = 2 } else if `npc' > 0 { local crit = 0 local criterion "none" if `npc' > wordcount("`clistn'") { local npc = wordcount("`clistn'") } } else { local crit = 8 } if "`scale'" != "" local scale "`cvarlist'" noi mata xtdcce2_rcce("`clistn'","`scale'","`touse'","`idvar' `tvar'",`crit',`npc',"`csa'","`numfac'") drop `clistn' unab clistn: `csa'* return local NumPc = `numfac' return local Type "`criterion'" local cross_structure 0 } if "`rctest'"!= "" { return matrix rctest = `rctest_results' return matrix rctest_det = `rctest_results'_det } return local varlist "`clistn'" return local cross_structure "`cross_structure'" end // ------------------------------------------------------------------------------------------------- // regularised CCE program // ------------------------------------------------------------------------------------------------- capture mata mata drop xtdcce2_rcce() mata: function xtdcce2_rcce(string scalar varnames, string scalar cvarlist, string scalar tousen, string scalar idtn,real scalar criterion,real scalar npc, string scalar csnames, string scalar numnames) { "start rcce" idt = st_data(.,idtn,tousen) idx = panelsetup(idt[.,1],1) N = panelstats(idx)[1] T = panelstats(idx)[3] T_min = panelstats(idx)[3] T_max = panelstats(idx)[4] ZbarL = st_data(.,varnames,tousen) if (cvarlist != "") { Z = st_data(.,cvarlist,tousen) } "data loaded" Sigma = J(cols(ZbarL),cols(ZbarL),0) T_min,T_max if (T_min:==T_max) { "panel balanced" Zbar = panelsubmatrix(ZbarL,1,idx) if (cvarlist != "") { "scale" for (i=1;i<=N;i++) { Zi = panelsubmatrix(Z,i,idx) ZZ = Zi:-Zbar Sigma = Sigma :+ quadcross(ZZ,ZZ) } } "Zbar loaded" } else { "panel unbalanced" cols(ZbarL) Zbar = J(T_max,cols(ZbarL),.) for (i=1;i<=N;i++) { Ti = panelsubmatrix(idt[.,2],i,idx) :- min(idt[.,2]) :+1 Zbari = panelsubmatrix(ZbarL,i,idx) Zbari ZZbar = Zbar[Ti,.] ///ZZbar if (hasmissing(Zbar)) { "add miss" tmp3 = selectindex(Zbari:!=.) tmp2 = Ti[tmp3] Zbar[tmp2,.] = Zbari[tmp3,.] } if (cvarlist!="") { Zi = panelsubmatrix(Z,i,idx) ZZ = Zi:-Zbari Sigma[Ti,.] = Sigma[Ti,.] :+ quadcross(ZZ,ZZ) } if (hasmissing(Zbar)==0 & cvarlist == "") i = N+1 } } if (cvarlist == "") { F = Zbar } else { Sigma = Sigma / (N*T_max) Sigma1 = invsym(sqrt(Sigma)) F = Zbar*Sigma1' } "F is" F ///fullsvd(quadcross(F,F)/T_max, uu_k, mus ,junk2) ///ER = J(1,MaxNumPC,.) ///for (mm1=MaxNumPC; mm1>=1; mm1--) { /// ER[mm1] = mus[mm1]/mus[mm1+1] ///} ///mockEV = mean(vec(Z):^2)/ln(min(N,T_min)); ///ER = (mockEV/mus[1], ER) ///maxindex(ER,1,NumPC,junk2) "criterion" criterion if (criterion > 0) { allICs0 = numfac_int(F,cols(ZbarL),5) allICs0 best_numfac0 = bestnum_ic_int(allICs0) ///best_numfac = (best_numfac0, allICs0[10,1]) NumPC = best_numfac0[criterion] } if (npc > 0) NumPC = npc "NumPC" NumPC /// Get eigenvectors and then real part eigensystem(quadcross(F',F')/T_max,Evec=.,Eval=.) Evec = Re(Evec) Fr = sqrt(T) * Evec[.,1..NumPC] /// Return to Stata idxv = st_addvar("double",csnames:+ strofreal((1..NumPC))) real matrix viewM, Vi st_view(viewM,.,idxv,tousen) if (T_min:==T_max) { for (i=1;i<=N;i++) { panelsubview(Vi,viewM,i,idx) Vi[.,.] = Fr } } else { for (i=1;i<=N;i++) { i panelsubview(Vi,viewM,i,idx) Ti = panelsubmatrix(idt[.,2],i,idx) :- min(idt[.,2]) :+1 viewM[Ti,.] = Fr[Ti,.] } } st_numscalar(numnames,NumPC) } end *** From xtnumfac mata: /// mean function which allows for missings function meanmiss(real matrix X) return(quadcolsum(X,0):/quadcolsum(X:!=.)) function mymean(real matrix X) return(mean(X)) function numfac_int(X0n, kmax0, stan) { "start numfac int" // numfac_int calculates the Bai&Ng (2002) and Ahn&Horenstein (2013) ICs for // the number of factors. // It has two inputs: // X0: A TxN matrix containing the data of interest. // kmax0: The maximum number of factors to consider. // The output is a matrix providing the IC values for factor models with // k=1,2,...,kmax0 factors in its rows. The columns correspond to the following // statistics: 1:PC_p1,...,6:IC_p3, 7:ER, 8:GR, 9: GOS T = rows(X0n) N = cols(X0n) minNT = min((N, T)) X0_s = X0n pointer mfunc if (hasmissing(X0_s)==0) mfunc = &mymean() else mfunc = &meanmiss() if (stan == 2 | stan == 3) X0_s = X0_s - J(T,1,1)*(*mfunc)(X0_s) if (stan == 4 | stan == 5) X0_s = X0_s - J(T,1,1)*(*mfunc)(X0_s) - (*mfunc)(X0_s')'*J(1,N,1) + J(T,1,1)*(*mfunc)(vec(X0_s))*J(1,N,1) if (stan == 3 | stan == 5) { X_sd = sqrt(((*mfunc)(X0_s:^2) - (*mfunc)(X0_s):^2))' X0_s = X0_s :/(J(T,1,1)*X_sd') } /// add zero mean column to X0 to ensure max number of factors can be used; see Remark 6, Juodis (2022) seed = rseed() X0 = X0_s,(rowsum(X0_s):* (2*runiformint(rows(X0_s),1,0,1):-1)):/cols(X0_s) rseed(seed) missind = X0 :== . missnum = sum(sum(missind)') st_numscalar("e(missnum)", missnum) if ( missnum == 0) { if (T > N) { xx = cross(X0,X0) fullsvd(xx:/(N*T), junk1, mus, junk2) // N x N } else { xx = cross(X0',X0') fullsvd(xx:/(N*T), junk1, mus ,junk2) // T x T } } else { obsind = J(T,cols(missind),1) - missind X0mean = J(T,1,1) * mean(editmissing(X0,0)) X0 = editmissing(X0,0) + X0mean:*missind conv_crit = (X0 - X0mean):^2 conv_crit = mean(mean(conv_crit)') upd = conv_crit while (upd > 0.001*conv_crit) { X0_old = X0 if (T > N) { xx = cross(X0,X0) fullsvd(xx:/(N*T), vee_k, mus, junk2) vee_k = vee_k[.,1..(kmax0+5)] uu_k = X0*vee_k/sqrt(N*T) } else { xx = cross(X0',X0') fullsvd(xx:/(N*T), uu_k, mus ,junk2) uu_k = uu_k[.,1..(kmax0+5)] vee_k = X0'*uu_k/sqrt(N*T) } X0 = X0_old:*obsind + (uu_k*vee_k'):*missind:*sqrt(N*T) upd = mean(mean(abs(X0-X0_old))') } } V_val = J(1,kmax0+1,.) // These are the three penalties (without mm0 or the estimate of sig2) penalties = ((N+T)/(N*T)*ln((N*T)/(N+T)) \ (N+T)/(N*T)*ln(minNT) \ ln(minNT)/minNT) for (mm0=kmax0; mm0>=1; mm0--) { V_val[mm0] = sum(mus[mm0+1..minNT]) } V_val if (kmax0+2=1; mm1--) { ER[mm1] = mus[mm1]/mus[mm1+1] mutildes[mm1] = mus[mm1]/V_val[1,mm1] GR[mm1] = ln(1+mutildes[mm1])/ln(1+mutildes[mm1+1]) } mockEV = V0/ln(minNT); ER = (mockEV/mus[1], ER) GR = (ln(1 + mockEV)/ln(1+ mutildes[1]), GR) allICs0 = ER \ GR return(allICs0) } // mata drop bestnum_ic_int() function bestnum_ic_int(allICs1) { // bestnum_ic_int picks an estimate for the number of factors from a matrix with IC // values for n increasing number of factors (starting at 0). // The function has one input: // - allICs1: a matrix containing the ICs corresponding to different // numbers of factors (in cols) for different ICs (rows). // We assume that the first 6 rows are the Bai&Ng ICs whereas // rows 7 and 8 are those of Ahn and Horenstein; // row 9 is the selection criterion used by GOS. // The function output is a 1x8 vector of estimates for the number of factors. best_numfac0 = J(1,2,.) tempmin = . ///for (jj=1; jj<=2; jj++) { /// minindex(allICs1[jj,.], 1, tempmin, junk1) /// best_numfac0[jj] = tempmin-1 ///} for (jj=1; jj<=2; jj++) { maxindex(allICs1[jj,.], 1, tempmin, junk1) best_numfac0[jj] = tempmin-1 } // selection rule for number of factors is: first number for which the difference is smaller than zero. // Here we count how many are larger than zero, which is eqaul to k(min|stat<0) because we have possibility of no factors as well. ///best_numfac0[9] = sum(allICs1[9,.]:>0) return(best_numfac0) } end ** 11. xtdcce2_csa creates cross-sectional averages capture mata mata drop xtdcce2_error_calc() mata: function xtdcce2_error_calc( string scalar varnames, /// string scalar csanames, /// string scalar touse, /// string scalar idvar, /// string scalar residname, /// real matrix xtdcce2_ebi, /// string scalar wbadj, /// |real scalar xb) { real matrix id real matrix vars real matrix csa real matrix residuals if (args()<7) xb = 0 vars = st_data(.,st_tsrevar(tokens(varnames)),touse) nocsa = 1 if (csanames[1,1] != "" ) { csa = st_data(.,csanames, touse) nocsa = 0 } id = st_data(.,idvar,touse) st_view(residuals,.,residname,touse) index = panelsetup(id,1) Nuniq = uniqrows(id) N_g = rows(Nuniq) K = cols(vars)-1 varj = J(0,K+1,.) i=1 while(i<=N_g) { /// partial out varsi = vars[(index[i,1]..index[i,2]),.] if (nocsa==0 ) { csai = csa[(index[i,1]..index[i,2]),.] tmp_xp = quadcross(csai,varsi) tmp_csa = quadcross(csai,csai) varsi = (varsi - csai*m_xtdcce_solver(tmp_csa,tmp_xp)) } if (xb == 0) { residuals[(index[i,1]..index[i,2]),.] = varsi[.,1] - varsi[.,(2..K+1)] * xtdcce2_ebi[i,(1..K)]' } else if (xb == 1 ) { /// here xb residuals[(index[i,1]..index[i,2]),.] = varsi[.,(2..K+1)] * xtdcce2_ebi[i,(1..K)]' } if (wbadj[1,1] == "wildbootstrap") { varsii = varsi[.,(2..K+1)] h = diagonal(varsii* m_xtdcce_inverter(quadcross(varsii,varsii)) * varsii') residuals[(index[i,1]..index[i,2]),.] = residuals[(index[i,1]..index[i,2]),.] :/ ( 1 :- h) } i++ } } end *** Program to adjust for wildbootstrap capture mata mata drop xtdcce2_wbsadj() mata: function xtdcce2_wbsadj( string scalar residnames, /// string scalar Xnames, /// string scalar idtvarname, /// string scalar touse) { real matrix resid st_view(resid,.,residnames,touse) X = st_data(.,Xnames,touse) idt = st_data(.,idtvarname,touse) index = panelsetup(idt[.,1],1) i = 1 "start loop" while (i<=rows(index)) { Xi = X[(index[i,1]..index[i,2]),.] h = diagonal(Xi * m_xtdcce_inverter(quadcross(Xi,Xi)) * Xi') resid[(index[i,1]..index[i,2]),.] = resid[(index[i,1]..index[i,2]),.] :/ (1 :- h) i++ } "done" } end *** checks if data is sorted, if not then sorts it capture program drop issorted program define issorted syntax varlist local sorted : dis "`:sortedby'" if "`sorted'" != "`varlist'" { noi disp "sort data" sort `varlist' } end *** program to copy mata content into variables given id and t variables capture mata mata drop xtdcce2_mata2stata() mata: function xtdcce2_mata2stata (string scalar varnames, real matrix source, string scalar idtstata, real matrix idtmata, string scalar touse , real scalar type,|real matrix numb) /// type: 0 residual, 1 coeff { /// check that varnames and source have same number of columns varnames if ((cols(tokens(varnames))!=cols(source)) * (type != 3)) { varnames = varnames[1,1]:+(strofreal(1..cols(source))) } else { varnames = tokens(varnames) } st_addvar("double", varnames) real matrix vars st_view(vars,.,varnames,touse) idt = st_data(.,idtstata,touse) index = panelsetup(idt[.,1],1) indexm = panelsetup(idtmata[.,1],1) Ni = uniqrows(idt[.,1]) N = rows(Ni) Nim = uniqrows(idtmata[.,1]) Nm = rows(Nm) i = 1 j = 1 real matrix varsi ///real mateix varsim ///if (type == 0) { while (i<=N) { idi = Ni[i] check = Nim:==idi if (sum(check) > 0) { /// ith element from Stata part, find in mata range /// find element in mata list /// select rows in mata list firstindex = selectindex(idtmata[.,1]:==idt[index[i,1],1])[1,1] indexmi = selectindex(indexm[.,1]:==firstindex) panelsubview(varsi,vars,i,index) varsim = panelsubmatrix(source,indexmi,indexm) if (type==2) { varsim = sqrt(diagonal(varsim))' } if (type==3) { ///varsim = (varsim)' varsim = varsim[numb[1],numb[2]] } /// check dimensions if (rows(varsim) ==1) { varsim = J(rows(varsi),1,varsim) varsi[.,.] = varsim } else if (rows(varsim):==rows(varsi)) { varsi[.,.] = varsim } else { idim_pos = xtdcce_selectindex(Nim:==idi) indexi = index[i,.] indexim = indexm[idim_pos,.] /// get t indicator ti = idt[|indexi[1,1],2 \ indexi[1,2],2|] tim = idtmata[|indexim[1,1],2 \ indexim[1,2],2|] t_unionm = xtdcce2_mm_which2f(tim,ti) t_unionm = t_unionm[xtdcce_selectindex(t_unionm)] t_union = xtdcce2_mm_which2f(ti,tim) varsi[t_union,.] = varsim[t_unionm,.] } } i++ } } end /// EM program from xtnumfac capture mata mata drop xtdcce2_EM() mata: function xtdcce2_EM(real matrix X0,real scalar N,real scalar T, real scalar kmax0,|string scalar msg_text) { if (args()==5) stata(sprintf(`"noi disp as smcl in gr " Missing values imputed for %s." "',msg_text)) missind = X0 :== . obsind = J(T,N,1) - missind X0mean = J(T,1,1) * mean(editmissing(X0,0)) X0 = editmissing(X0,0) + X0mean:*missind conv_crit = (X0 - X0mean):^2 conv_crit = mean(mean(conv_crit)') upd = conv_crit while (upd > 0.001*conv_crit) { X0_old = X0 if (T > N) { xx = cross(X0,X0) fullsvd(xx:/(N*T), vee_k, mus, junk2) vee_k = vee_k[.,1..(kmax0+5)] uu_k = X0*vee_k/sqrt(N*T) } else { xx = cross(X0',X0') fullsvd(xx:/(N*T), uu_k, mus ,junk2) uu_k = uu_k[.,1..(kmax0+5)] vee_k = X0'*uu_k/sqrt(N*T) } X0 = X0_old:*obsind + (uu_k*vee_k'):*missind:*sqrt(N*T) upd = mean(mean(abs(X0-X0_old))') } return(X0) } end cap program drop xtdcce2_absorb_prog program define xtdcce2_absorb_prog, rclass syntax anything(name=absorb) , [ TRACEhdfeopt partialonly] touse(string) vars(string) [donotoverwrite] local singeltons = 0 if "`keepsingeltons'" == "" local singeltons = 1 local tracehdfe = 0 if "`tracehdfeopt'" != "" local noii noi *** tempnames for mata objects tempname xtdcce2_absorb cap which reghdfe loc rc = _rc cap which ftools if _rc | `rc' { di as err "option {it: absorb()} requires {help:reghdfe} and {help ftools}:" di as err " click {stata ssc install reghdfe} to install from SSC" di as err " click {stata ssc install ftools} to install from SSC" exit 199 } cap include "reghdfe.mata", adopath cap { mata: `xtdcce2_absorb' = FixedEffects() mata: `xtdcce2_absorb'.absvars = "`absorb'" mata: `xtdcce2_absorb'.tousevar = "`touse'" mata: `xtdcce2_absorb'.init() mata: `xtdcce2_absorb'.partial_out("`vars' ",0, 0) } if _rc { di as err "{bf:reghdfe} Mata library not found or error in {cmd:reghdfe}." exit 199 } if "`noii'" != "" { noi disp "Before reghdfe partial out" noi sum `vars' } mata st_local("var_partial",invtokens("abs":+strofreal(1..cols(tokens("`vars'"))))) mata st_store(`xtdcce2_absorb'.sample, st_addvar("double",tokens("`var_partial'")),"`touse'", `xtdcce2_absorb'.solution.data) if "`noii'" != "" { noi disp "After reghdfe partial out" noi mata mean(`xtdcce2_absorb'.solution.data) noi sum `var_partial' } if "`partialonly'" != "" { error 199 } mata mata drop `xtdcce2_absorb' if "`donotoverwrite'" == "" { local i = 1 foreach source in `var_partial' { local aim = word("`vars'",`i') replace `aim' = `source' local i = 1 + `i' } } return local absorb_vars "`var_partial'" end /// RC test mata: function xtdcce2_rctest(string scalar yxvarsn, string scalar csan, string scalar Wn, string scalar tousen, string scalar idtn, real scalar criterion , real scalar boot, real scalar stand, real scalar trace, string scalar resultsn ) { "Rank Test Program" real matrix results, idt, idx, YX, Z, Zbar, YXD, W, Zi, YXi,Wi, sigma, tmp, tmp2, tmp3, A1, A2, V,D,B, C, V1, D1, V2, D2, V3, D3, xx1, pval, ix, Ti, YXL real scalar N,T, T_min,T_max, i, K, n0, reject, cnt /// output real scalar m, p, rc timer_on(20) st_view(idt,.,idtn,tousen) st_view(Z,.,csan,tousen) st_view(YX,.,yxvarsn,tousen) st_view(W,.,Wn,tousen) if (cols(W)==1) W = J(1,cols(Z),W) idx = panelsetup(idt[.,1],1) N = panelstats(idx)[1] T = panelstats(idx)[4] T_min = panelstats(idx)[3] T_max = panelstats(idx)[4] K = cols(Z) timer_on(21) if (trace==1) sprintf("Dimensions T = %s, N= %s, K=%s",strofreal(T_max),strofreal(N),strofreal(K)) sigma = J(T_max*K,T_max*K,0) Zbar = J(T_max,K,0) if (T_max:==T_min) { "balanced" Zbar = panelsubmatrix(Z,1,idx) for (i=1;i<=N;i++) { panelsubview(Wi,W,i,idx) panelsubview(YXi,YX,i,idx) ///vec(Wi:*YXi :- Wi :* Zbar) tmp = vec(Wi:*YXi :- Wi :* Zbar)' ///quadcross(tmp,tmp) sigma = sigma + quadcross(tmp,tmp) } sigma= sigma/N YXL = YX YXL = colshape(YXL',T_max)' } else { YXL = J(T_max,K*N,.) cnt = 1 Zbar = J(T_max,K,0) min_val_ti = min(idt[.,2]) for (i=1;i<=N;i++) { i,T_max,T_min,K,cnt,N panelsubview(Ti,idt[.,2],i,idx) panelsubview(Zi,Z,i,idx) panelsubview(Wi,W,i,idx) panelsubview(YXi, YX,i,idx) /// ensure Ti always starts with 1 if (min_val_ti>1) Ti = Ti :- min_val_ti:+1 YXL[Ti,cnt..cnt-1+cols(YXi)] = YXi cnt = cnt + cols(YXi) tmp = vec(Wi:*YXi :- Wi :* Zi)' Tii = J(K,1,1)#Ti :+ (((1..K)':-1)*T_max)#J(rows(Ti),1,1) sigma[Tii,Tii] = sigma[Tii,Tii] :+ quadcross(tmp,tmp) :/ rows(Ti) /// buid CSA tmp3 = selectindex((rowmissing(Zi):==0)) tmp2 = Ti[tmp3] Zbar[tmp2,.] = Zi[tmp3,.] ///Wi = Wi[Ti,.] //YXi = YXi[Ti,.] //Zi = Zi[Ti,.] ///sigma[Ti,Ti] = sigma[Ti,Ti] + (quadcross(Wi,YXi) * quadcross(Wi,Zi)' ) / N ///if (hasmissing(Zbar)==0) i = N+1 } "done" } timer_off(21) /// Number of common factors timer_on(22) m = bestnum_ic_int(numfac_int(YXL,7,stand))[criterion] if (trace==1) sprintf("Estimated number of common factors %f",m) timer_off(22) timer_on(23) /// Estimation of p A1 = Zbar*Zbar' A2 = quadcross(Zbar,Zbar) results = J(K,4,.) n0 = 0 reject = 1 timer_off(23) timer_on(24) while (n0 < K & reject == 1) { xtdcce2_eigenshuffle(&A1,D1=.,V1=.) "D1" rows(D1),cols(D1) ///mean(D1) "V1" rows(V1),cols(V1) ///mean(V1) C = V1[.,n0+1..cols(V1)] /// check if Re() is correct results[n0+1,1] = Re(N*sum(D1[n0+1..min((T,K))])) timer_on(26) /// Bootstrap Distribution xtdcce2_eigenshuffle(&A2,D2=.,V2=.) D = V2[.,n0+1..cols(V2)] B = (D'#C')*sigma*(D#C) timer_on(28) xtdcce2_eigenshuffle(&B,D3=.,V3=.) timer_off(28) timer_on(29) xx1 = colsum((D3[.,1] * J(1,boot,1) :* rchi2(rows(D3),boot,1) ))' timer_off(29) timer_on(27) results[n0+1,2] = mm_quantile(Re(xx1),1,0.95) timer_off(27) tmp = Re(xx1)\results[n0+1,1] tmp = tmp,(1::(boot+1)) tmp = sort(tmp,-1) tmp[.,2]:==(boot+1) ix = selectindex(tmp[.,2]:==(boot+1)) pval = 1 - ix/(boot+1) results[n0+1,3] = pval timer_off(26) /// Decision if (results[n0+1,1] > results[n0+1,2] ) { results[n0+1,4] = 1 n0 = n0 + 1 } else { results[n0+1,4] =0 reject =0 } } timer_off(24) timer_on(25) p = sum(results[.,4]) st_matrix(resultsn,(1-(pprct") st_matrixcolstripe(resultsn+"_det",cnames) st_matrixrowstripe(resultsn+"_det",rnames) timer_off(25) timer_off(20) } void xtdcce2_eigenshuffle(transmorphic mat, real matrix Eval, real matrix Evec) { real matrix idx if (eltype(mat)== "real") eigensystem(mat,Evec=.,Eval=.) else if (eltype(mat)== "pointer") eigensystem( (*mat),Evec=.,Eval=.) else _error(3250,"Matrix has to be real or pointer.") idx = order(Eval',-1) Eval = Eval[idx]' Evec = -Evec[idx,.] } end