capture program drop FGT_CI program define FGT_CI, eclass properties(svyb) version 13.1 syntax varlist(min=1 numeric fv) [if] [in] [pweight iweight], rankvar(varname numeric) [method(string) cutoff(real 0) power(real 0) modpart1(string) modpart2(string) boot_reps(integer 250) boot_seed(integer 852015) strata(varname) psu(varname) bsw_average(integer 10) noboot noresults table(string) table_opt(string)] * The first variable in varlist must be the health-related variable one wants to compute the CI * The following variables in varlist are the covariates to decompose the health-related variable * Note that factor variables are being allowed * Non-factor variables are treated as continuous covariates * Factor variables are treated as discrete covariates * OPTIONS * method indicates which concentration index to compute and decompose. * "standard" refers to the concentration index of the untransformed dependent varialbe * "threshold" refers to the FGT transformation defined above a cutoff value (e.g. body mass index above 30) * "ceiling" referes to the FGT transformation defined below a cutoff value (e.g. body mass index below 18.5) * ceiling sets the cutoff value under which differences are counted. This option cannot be specified simulateneously with threshold. * thresold indicates whether the cutoff value is a threshold (if 1) or a ceiling (if 0). Default is 1 (threshold). * power indicates which FGT power to use. Default is zero (status). * rankvar specifies the ranking variable for the CI calculation * modpart1 specifies the model used in the first part of the model. Default is logit. * modpart2 specifies the model used in the first part of the model. Default is reg. * For both parts, follow the specification of twopm.ado. * Bootstap options (boostrapping is mandatory as standard errors reported with a single estimate are incorrect) * boot_reps: is for the number of bootstrap repetitions, default value is 250 * boot_seed: sets the seed for the bootstrap, default value is 852015 * strata: indicates the strata variable (optional) * psu: indicates the primary sampling unit variable (optional) * bsw_average: is for the number of weights that are averaged in the mean bootstrap. Default value is 10. * noboot: indicates whether no boostrap is going on. Do not let the user setting this value, this is set internally to avoid an infinite number of bootstraps * Results options * noresults supresses the estimation results. * table(string) displays an aggregate result table and saves it under the name imputed as a string. * If string is "nosave" the option only displays the table without saving it. * If string is "", the table is neither displayed or saved. * Default value is "". * table_opt(string) options for esttab command. *** Body of the function *** * 0) Initialization marksample touse qui su `touse' local nobs = r(sum) * Prepare the weight variable for the concentration index if ("`weight'" != "") { local CIweight "aweight" } * Prepare the weight variable for the bootstrap local boot_wt "`exp'" local boot_wt: subinstr local boot_wt "=" "" tempvar boot_weight if ("`boot_wt'" == "") { gen `boot_weight' = 1 } else { gen `boot_weight' = `boot_wt' } qui replace `boot_weight' = 0 if !`touse' local boot_wt "`boot_weight'" * Retrieve the function's arguments without weights for svy bootstrap local arguments "`0'" gettoken arg_part1 arguments: arguments, parse("[") gettoken weights arg_part2: arguments, parse(",") * Check arguments * Separate dependent variable from covariates gettoken y covariates: varlist qui su `y' if `touse' if (r(min)<0) { di as error "warning: depend variable `y' contains negative values." } qui su `y' if `touse' if (r(min)<0) { di as error "warning: depend variable `y' contains negative values." } qui su `rankvar' if `touse' if (r(min)<0) { di as error "warning: rankvar contains negative values." } * Options if ("`method'" == "") { local method "standard" } else { if (!("`method'" == "standard" | "`method'" == "threshold" | "`method'" == "ceiling")) { di as error "Option method must be either "standard", "threshold", or "ceiling." exit } } if (`power'<0) { di as error "Option power must be non-negative." exit } if ("`modpart1'"=="") { local modpart1 "logit" local modpart1_method "logit" } else { gettoken modpart1_method modpart1_options: modpart1, parse(",") } if ("`modpart2'"=="") { local modpart2 "regress" local modpart2_method "regress" } else { gettoken modpart2_method modpart2_options: modpart2, parse(",") } if (`boot_reps'<3) { di as error "Option boot_reps must be at least 3." exit } if (`boot_seed'<=0) { di as error "Option boot_seed must be non-negative." exit } if (`bsw_average'<=0) { di as error "Option bsw_average must be non-negative." exit } if ("`results'" == "noresults") { local results "quietly" } * 1) Create all indicator variables local covarnames "" // list of covariate names stripped of the leading "i." local nonfactnames "" // list of quantitative and binary variables local factnames "" // list of factor variable names stripped of the leading "i." local modvars "" // list of covariate names including indicators for factor variables local nbfactvars = 0 // number of factor variables specified by the user foreach var of local covariates { gettoken pref v: var, parse(".") gettoken period v: v, parse(".") if ("`pref'" == "i") { local ++nbfactvars local covarnames "`covarnames' `v'" local factnames "`factnames' `v'" qui tab `v', gen(__I`v'_) forvalues cat = 2/`r(r)' { local modvars "`modvars' __I`v'_`cat'" } } else { local covarnames "`covarnames' `var'" local nonfactnames "`nonfactnames' `var'" local modvars "`modvars' `var'" } } * 2) Create the FGT variable tempname FGTy if ("`method'" == "standard") { gen `FGTy' = `y' } else { gen `FGTy' = 0 if ("`method'" == "threshold") { qui replace `FGTy' = (`y'-(`cutoff'))^(`power') if `y' >= `cutoff' } else { * method == "ceiling" qui replace `FGTy' = (`cutoff'-(`y'))^(`power') if `y' <= `cutoff' } } * 3) Calculate the overal FGT-CI tempname CFGTy qui concindc `FGTy' if `touse' [`CIweight' `exp'], welfarevar(`rankvar') matrix `CFGTy' = (r(concindex)) matrix colnames `CFGTy' = total matrix coleq `CFGTy' = CIy * 4) If indepvars have been specified, decompose the total CI if ("`covariates'" != "") { * 4.1) Estimation if ("`method'" == "standard") { if ( "`modpart2_options'" == "") { local comma "," } `results' `modpart2_method' `FGTy' `modvars' if `touse' [`weight' `exp'] `modpart2_options' `comma' } else { if (`power'==0) { if ( "`modpart1_options'" == "") { local comma "," } `results' `modpart1_method' `FGTy' `modvars' if `touse' [`weight' `exp'] `modpart1_options' `comma' } else { `results' twopm `FGTy' `modvars' if `touse' [`weight' `exp'], firstpart(`modpart1') secondpart(`modpart2') } } * 4.2) Calculate the elasticities tempname elast eyex qui margins if `touse' [`weight' `exp'], eyex(*) post matrix `elast' = e(b) matrix `eyex' = `elast'[1,1...] matrix drop `elast' matrix coleq `eyex' = eyex * 4.3) Calculate the concentration index for each covariate and their contribution to the overall CI tempname CIk // concentration index for each covariate matrix `CIk' = `eyex' matrix coleq `CIk' = CIk tempname CIy // contribution of each covariate to the overall CI matrix `CIy' = `eyex' matrix coleq `CIy' = CIy local i = 1 foreach var of local modvars { qui concindc `var' if `touse' [`CIweight' `exp'], welfarevar(`rankvar') matrix `CIk'[1,`i'] = r(concindex) matrix `CIy'[1,`i'] = `eyex'[1,`i'] * r(concindex) local ++i } * 4.4) Aggregate the contributions of the factor variables, if any, and total contribution of all variables tempname CIy_tot if ("`factnames'" != "") { tempname CIy_fact matrix `CIy_fact' = J(1,`nbfactvars',0) matrix colnames `CIy_fact' = `factnames' matrix coleq `CIy_fact' = CIy_factvar } local fact = 0 matrix `CIy_tot' = (0) foreach var of local covariates { gettoken pref v: var, parse(".") gettoken period v: v, parse(".") if ("`pref'" == "i") { local ++fact qui tab `v' forvalues cat = 2/`r(r)' { matrix `CIy_fact'[1,`fact'] = `CIy_fact'[1,`fact'] + `CIy'[1,"CIy:__I`v'_`cat'"] matrix `CIy_tot' = `CIy_tot' + `CIy'[1,"CIy:__I`v'_`cat'"] } } else { matrix `CIy_tot' = `CIy_tot' + `CIy'[1,"CIy:`var'"] } } * 4.5) Calculation of the regression residuals tempname residual matrix `residual' = `CFGTy' - `CIy_tot' matrix colnames `residual' = residual matrix coleq `residual' = CIy capture drop __I* } * 5) Bootstrap (only do it when option noboot is not specified, that is when macro boot is empty and does not contain "noboot" if ("`boot'" == "") { * Set the survey if ("`psu'" == "") { tempvar psu gen `psu' = _n } if ("`strata'" == "") { tempvar strata gen `strata' = 1 } quietly svyset `psu' [pweight=`boot_wt'], strata(`strata') * Compute the bootstrap replication weights * Check bsweights bsweights ___bsw, reps(`boot_reps') n(-1) balanced double average(`bsw_average') seed(`boot_seed') dots replace quietly svyset [pweight=`boot_wt'], bsrweight(___bsw*) bsn(`bsw_average') `results' svy bootstrap: FGT_CI `arg_part1' `arg_part2' noboot drop ___bsw* } * 6) Return the results tempname b V if ("`boot'" == "") { * For final results * Take the boostrapped variance-covariance matrix matrix `b' = e(b) matrix `V' = e(V) * Display an aggregate table of results if ("`covariates'" != "") { if ("`table'"=="nosave") { esttab, b(%9.3f) se(%9.3f) star(* 0.1 ** 0.05) order(`modvars' residual total) unstack label nonumbers nodepvars `table_opt' } else if ("`table'"!="") { esttab using "`table'", b(%9.3f) se(%9.3f) star(* 0.1 ** 0.05) order(`modvars' residual total) unstack label nonumbers nodepvars `table_opt' } } } else { * For boostrap iterations if ("`covariates'" != "") { if ("`factnames'" != "") { matrix `b' = (`CIk', `eyex', `CIy', `residual', `CFGTy', `CIy_fact') } else { matrix `b' = (`CIk', `eyex', `CIy', `residual', `CFGTy') } } else { matrix `b' = (`CFGTy') } * Create fake variance-covariance matrix for individual bootstrap replications local colnames: colfullnames `b' matrix `V' = I(colsof(`b')) matrix colnames `V' = `colnames' matrix rownames `V' = `colnames' } ereturn post `b' `V', depname(`y') obs(`nobs') esample(`touse') ereturn local cmd "FGT_CI" end