📄 mfx.ado
字号:
*! version 2.1.2 01jul2005
program define mfx, eclass
version 8.2, missing
local ver : display string(_caller())
global T_mfver "version `ver', missing:"
version 6, missing
gettoken cmd : 0, parse(" ,")
if `"`cmd'"'=="," | "`cmd'"=="" {
local cmd compute
}
else gettoken cmd 0 : 0, parse(" ,")
local l = length("`cmd'")
if substr("replay",1,`l')==`"`cmd'"' {
Replay `0'
}
else if substr("compute",1,`l')=="`cmd'" {
Compute `0'
}
else if "`cmd'"=="if" | "`cmd'"=="in" {
Compute `cmd' `0'
}
else {
di in red `"unknown mfx subcommand `cmd'"'
exit 198
}
end
*----------------------------------------------------------
program define Compute, eclass
syntax [if] [in] [, AT(string) EQlist(string) PREDict(string) /*
*/ VARlist(string) dydx eyex dyex eydx NONLinear noDiscrete /*
*/ noEsample noWght noSe DIAGnostics(string) /*
*/ TRacelvl(int 0) noDROP force Level(cilevel) ]
if "`e(cmd)'" == "" {
error 301
}
if `"`e(prefix)'"' == "" {
local cmd = "`e(cmd)'"
}
else {
local cmd = "`e(prefix)':`e(cmdname)'"
}
if (!has_eprop(b) | (!has_eprop(V) & "`se'" == "") | "`e(predict)'"=="_no_predict") {
dis in red "mfx not available after `cmd'"
exit 119
}
*---- mfx not supported after all estimation commands
if e(cmd)=="canon" | e(cmd)=="boxcox" | e(cmd)=="nl" | e(cmd)=="svar" /*
*/ | e(cmd)=="vec" {
dis in red "mfx not available after " e(cmd)
exit 119
}
*---- options
local type "`dydx'`eyex'`dyex'`eydx'"
if "`type'" == "" {
local type "dydx"
}
else if length("`type'") != 4 {
dis in red "dydx, eyex, dyex, eydx are mutually exclusive"
exit 198
}
if "`type'" == "dydx" | "`type'" == "dyex" {
local lny 0
}
else local lny 1
if ("`type'" != "dydx") {
local discret "nodiscret"
}
if ("`diagnostics'"=="beta" | "`diagnostics'"=="drop" /*
*/ | "`diagnostics'"=="vce" | "`diagnostics'"=="all") {
local diag `"`diagnostics'"'
}
else {
if ("`diagnostics'"!="beta" & "`diagnostics'"!="drop" /*
*/ & "`diagnostics'"!="vce" & "`diagnostics'"!="all" /*
*/ & "`diagnostics'"!="" ) {
dis in red "option `diagnostics' not "/*
*/"allowed in diagnostics"
exit 198
}
else {
local diag
}
}
if "`tracelvl'"!="" {
local trace `tracelvl'
}
else {
local trace
}
if ("`e(cmd2)'"=="streg" & "`predict'"=="hr") | /*
*/ substr("`predict'",1,3)=="std" {
local nonline "nonlinear"
}
*---- Clear previous mfx results
local oldtype `e(Xmfx_type)'
local list X `oldtype' se_`oldtype' type method dummy variables
local list `list' predict label_p cmd discrete y off off1 off2 nodrop
foreach res of local list {
est local Xmfx_`res'
}
*---- Preserve original dataset
preserve
*---- Check that dataset contains some observations for at points
marksample touse, novarlist
if "`at'"=="" | "`at'"=="mean" | "`at'"=="median" |/*
*/("`e(offset)'"!="" | "`e(offset2)'"!="" |/*
*/ "`e(offset1)'"!="" & index("`predict'", "nooffset")==0) {
if "`esample'"=="" {
qui count if `touse' & e(sample)
}
else qui count if `touse'
if r(N)==0 {
di as error "no observations"
exit 2000
}
}
else {
qui count
if r(N)==0 {
di as error "no observations"
exit 2000
}
}
*---- get label for predict before any changes to e(cmd)
if "`force'" == "" {
tempname junk
$T_mfver cap noi qui predict `junk', `predict'
if _rc!=0 {
exit _rc
}
else local labelp : variable label `junk'
}
*---- preserve original estimates
tempname origest
est hold `origest', copy
*---- Parse varlist and eqlist
tempname B ism isv
mat `B' = e(b)
local cnum = colsof(`B')
mat `ism' = J(1, `cnum',0)
mat `isv' = J(1, `cnum',0)
/* ism[1,i]!=0 if not repeated variable */
/* isv[1,i]=1 if variable is to be computed */
GetEq `ism' `isv' "`eqlist'" "`varlist'" `esample'
local xscol "`s(xscol)'" /* colnames of Xs of interest */
local total `s(total)' /* # of Xs of interest */
local xfull "`s(xfull)'" /* varnames of all Xs */
local totfull `s(totfull)' /* # of all Xs */
local dummy "`s(dummy)'" /* 0 continuous 1 dummy */
local flag "`s(flag)'" /* 1 nonlinear 0 linear */
if `total' == 0 {
dis in red "no independent variables"
exit 102
}
if "`nonline'" != "" {
local flag = 1
}
*---- Get point at which to evaluate
tempname X
mat `X' = J(1, `totfull', 0)
mat colnames `X' = `xfull'
if "`at'" == "" {
local at "mean"
}
at `X' "`totfull'" "`at'" "if `touse', `esample' `wght'"
tempname matat X matatse
mat `matat' = r(at)
mat `X' = r(X)
mat `matatse' = r(at)
/* matat is same shape as e(b) */
/* X has no entries for repeated variables */
*---- Will need to check if predict option depends on dependent vars,
*---- covariance matrix and/or stored scalars. If so, then the
*---- predict option is not suitable for standard errors.
tempname copy
mat `copy' =`X'
if "`se'" == "" & "`force'" == "" {
Checkse_at `copy' "`totfull'" "`at'" /*
*/ "`touse'" "`esample'" "`wght'"
mat `matatse' = r(A)
}
*---- Look for Time series ops in indep vars.
*---- Change to svy for internal est command so estimates can be reposted.
EstPost `matat' `matatse'
*---- Check prediction for error now that estimates have been reposted
if "`force'" == "" {
tempname junk
$T_mfver cap noi qui predict `junk', `predict'
if _rc!=0 {
est unhold `origest'
exit _rc
}
}
*---- Replace offset with mean
if ("`e(offset)'"!="" | "`e(offset1)'"!="" /*
*/ | "`e(offset2)'"!="") /*
*/ & index("`predict'", "nooffset")==0 {
MeanOffset if `touse', `esample' `wght'
foreach x in "" "1" "2" {
if "`r(avoff`x')'"!="" {
local avoff`x' = r(avoff`x')
}
}
}
*---- Check if predict is constant across e(sample). If so, then
*---- predict option is suitable for marginal effects
if "`force'" == "" {
Checkdfdx `matat' "`predict'" `diag'
if `r(donotdydx)'==1 {
di as error "predict() expression `predict'" in /*
*/ smcl " {help j_mfxunsuit##|_new:unsuitable}" /*
*/ as error " for marginal-effect" /*
*/ " calculation"
est unhold `origest'
exit 119
}
if `r(donotdrop)'==1 {
local drop="nodrop"
if `trace'>0 {
di as text _n "note: nodrop option enforced"
}
}
}
*---- Drop dataset
qui keep if e(sample) /*some only predict into the e(sample) */
/* so need obs 1 to be in e(sample) */
if "`drop'"=="" {
if ("`diag'"=="drop" | "`diag'"=="all") {
di as text _n "Kept first e(sample) observation only."
}
qui keep in 1
}
else {
if ("`diag'"=="drop" | "`diag'"=="all") {
di as text _n "All e(sample) observations " /*
*/ "kept: N = " _c
count
}
}
*---- Calculate predicted value at evaluation point.
tempname y
GetY `y' `matat' "`predict'"
if (`y' <= 0) & `lny' {
dis in red "y = " `y' " < 0, `type' not available"
exit 459
}
*---- Calculate marginal effect dydx
if `flag' {
NL_dfdx `matat' `ism' `isv' "`dummy'" `total' /*
*/ "`predict'" "`discret'" `trace'
}
else {
L_dfdx `matat' `ism' `isv' "`dummy'" `total' /*
*/ "`predict'" "`discret'" `trace'
tempname dfdxb
mat `dfdxb' = r(dfdxb)
}
tempname dfdx
mat `dfdx' = r(dfdx)
*---- Check if prediction option suitable for standard errors
if "`se'" == "" & "`force'" == "" {
Checkse_est `matatse' `touse' `flag' `ism' `isv' `dfdx' /*
*/ "`dummy'" `total' "`predict'" "`discret'"
tempname newdfdx
mat `newdfdx' = e(dfdx)
if ("`diag'"=="vce" | "`diag'"=="all") {
di _n _n as text "Check prediction function does "/*
*/ "not depend on dependent variables, "/*
*/ _n "covariance matrix or stored scalars."/*
*/ _n "dfdx: "
mat list `dfdx', noheader nonames
di _n _n as text "dfdx, after resetting dependent "/*
*/ "variables, covariance matrix and "/*
*/ "stored scalars: "
mat list `newdfdx', noheader nonames
di _n _n as text "Relative difference = " _c /*
*/ as result mreldif(`dfdx',`newdfdx') _n
}
capture assert mreldif(`dfdx',`newdfdx') < 1e-10
if _rc {
di as text _n "warning: predict() expression "/*
*/ "`predict'" in smcl /*
*/ " {help j_mfxunsuitse##|_new:unsuitable} " /*
*/ as text "for standard-error calculation;"/*
*/ _n "option nose imposed" _n
local se="nose"
}
}
*---- Calculate standard errors
if "`se'" == "" {
if `flag' {
NL_se `matat' `ism' `isv' "`dummy'" `total' /*
*/ "`predict'" "`discret'" `lny' `trace'
}
else {
L_se `matat' `ism' `isv' "`dummy'" `total' /*
*/ "`predict'" "`discret'" `lny' `dfdxb' `trace'
}
tempname se_dfdx
mat `se_dfdx' = r(se_dfdx)
}
*---- Restore original estimates
est unhold `origest'
*---- Calculate elasticities if required
local i = 1
while `i' <= colsof(`X') {
if "`type'" == "eyex" {
mat `dfdx'[1,`i'] = `X'[1,`i']/`y' * `dfdx'[1,`i']
}
if "`type'" == "dyex" {
mat `dfdx'[1,`i'] = `X'[1,`i'] * `dfdx'[1,`i']
}
if "`type'" == "eydx" {
mat `dfdx'[1,`i'] = `dfdx'[1,`i']/`y'
}
local i = `i' + 1
}
mat colnames `dfdx' = `xscol'
if "`se'" == "" {
local i = 1
while `i' <= colsof(`X') {
if "`type'" == "eyex" {
mat `se_dfdx'[1,`i']=`X'[1,`i'] /*
*/ *`se_dfdx'[1,`i']
}
if "`type'" == "dyex" {
mat `se_dfdx'[1,`i']=`X'[1,`i'] /*
*/ *`se_dfdx'[1,`i']
}
local i = `i' + 1
}
mat colnames `se_dfdx' = `xscol'
}
*---- Return results
local vars
tempname B
mat `B' = e(b)
local cnum = colsof(`B')
local i 1
while `i' <= `cnum' {
if `ism'[1,`i'] != 0 {
if `isv'[1,`i']==1 {
local vars `vars' 1
}
else local vars `vars' 0
}
local i = `i' + 1
}
est mat Xmfx_X `X'
local cnum = colsof(`dfdx')
forvalues i= 1/`cnum' {
local isvar : word `i' of `vars'
if `isvar'==0 {
mat `dfdx'[1,`i']=.
}
}
est mat Xmfx_`type' `dfdx'
if "`se'" == "" {
local cnum = colsof(`se_dfdx')
forvalues i= 1/`cnum' {
local isvar : word `i' of `vars'
if `isvar'==0 {
mat `se_dfdx'[1,`i']=.
}
}
est mat Xmfx_se_`type' `se_dfdx'
}
if `flag' {
est local Xmfx_method "nonlinear"
}
else est local Xmfx_method "linear"
est local Xmfx_variables "`vars'"
est local Xmfx_dummy "`dummy'"
est local Xmfx_predict "`predict'"
est local Xmfx_label_p "`labelp'"
est local Xmfx_cmd "mfx"
if "`discret'" == "" {
est local Xmfx_discrete "discrete"
}
else est local Xmfx_discrete "nodiscrete"
est local Xmfx_type "`type'"
est scalar Xmfx_y = `y'
if "`drop'" != "" {
est local Xmfx_nodrop="nodrop"
}
foreach x in "" "1" "2" {
if "`avoff`x''"!="" {
est scalar Xmfx_off`x'=`avoff`x''
}
}
if "`level'" != "" {
local level "level(`level')"
}
Replay , `level'
capture mac drop T_mfver
Clean
restore
end
*----------------------------------------------------------
program define Checkdfdx, rclass
args X predict diag
tempname junk junk1 junk2 junkn mean mean1 meann
*---- Put mean in obs 1 only
preserve
qui keep if e(sample)
AddXck `X' 1
$T_mfver qui predict double `junk1', `predict'
scalar `mean1'=`junk1'[1]
restore
*---- Put mean in last obs only
preserve
qui keep if e(sample)
local N=_N
AddXck `X' `N'
$T_mfver qui predict double `junkn', `predict'
scalar `meann'=`junkn'[_N]
restore
*---- Put mean in all obs
preserve
AddXck `X'
$T_mfver qui predict double `junk', `predict'
qui summ `junk' if e(sample)
scalar `mean'=r(mean)
if ("`diag'"=="beta" | "`diag'"=="drop" | "`diag'"=="all") {
di as text _n _col(10) "Predict into observation 1 = " /*
*/ as result `mean1'
}
if ("`diag'"=="beta" | "`diag'"=="all") {
di as text _col(7) "Predict into last observation = " /*
*/ as result `meann'
di as text "Predict into all observations: mean = " /*
*/ as result `mean'
di as text _col(3) "Predict into all observations: sd = " /*
*/ as result r(sd)
}
*---- Check if predicts are same value
if r(sd)>1e-10 | abs(`mean'-`mean1')>1e-10 | /*
*/ abs(`mean'-`meann')>1e-10 {
return local donotdydx =1
}
else {
return local donotdydx =0
qui keep if e(sample)
qui keep in 1
$T_mfver cap qui predict double `junk2' , `predict'
if _rc==0 {
if ("`diag'"=="drop" | "`diag'"=="all") {
di as text _n _col(7) "Predict into obs 1 "/*
*/"after drop = " as result `junk2'[1]
}
if `junk2'[1] != `mean1' {
return local donotdrop =1
}
else return local donotdrop =0
}
else {
if ("`diag'"=="drop" | "`diag'"=="all") {
di as text _n "Predict error after drop."
}
return local donotdrop =1
}
}
restore
end
program define AddXck
args X a
local cname : colnames `X'
tokenize "`cname'"
if "`a'"=="" {
local where = ""
}
else local where = "in `a'"
local j=1
while "``j''" != "" {
if "``j''" != "_cons" {
cap confirm var ``j''
local rc1 = _rc
if `rc1' == 0 {
qui replace ``j'' = `X'[1,`j'] `where'
}
else {
cap confirm new var ``j''
local rc2 = _rc
if `rc2' == 0 {
tempvar junk
qui gen double `junk' = /*
*/ `X'[1,`j'] `where'
cap drop ``j''
rename `junk' ``j''
}
}
}
local j = `j' + 1
}
end
*----------------------------------------------------------
program define Checkse_at, rclass
args X total at touse esample wght
preserve
tsrevar `e(depvar)', list
if "`r(varlist)'"~="" {
foreach k of varlist `r(varlist)' {
capture replace `k' = 0
}
}
qui at `X' "`total'" "`at'" "if `touse', `esample' `wght'"
tempname i
mat define `i'=r(at)
ret mat A = `i'
restore
end
*----------------------------------------------------------
program define Checkse_est, eclass
args matatse touse flag ism isv dfdx dummy /*
*/ total predict discret
tempname V oldest
est hold `oldest', copy
preserve
EstPost_se
mat `V' = e(V)
local k = colsof(`V')
mat `V'[1,1] = I(`k')
est repost V = `V'
local scalars : e(scalars)
foreach s of local scalars {
if e(`s')~=int(e(`s')) {
est local `s'
}
}
tempname junk A
$T_mfver cap qui predict double `junk' , `predict'
if _rc!=0 {
mat `A' = J(1,`total', .)
}
else {
if `flag' {
qui NL_dfdx `matatse' `ism' `isv' "`dummy'" /*
*/ `total' "`predict'" "`discret'" 0
}
else {
qui L_dfdx `matatse' `ism' `isv' "`dummy'" /*
*/ `total' "`predict'" "`discret'" 0
}
mat define `A'=r(dfdx)
}
restore
est unhold `oldest'
est mat dfdx =`A'
end
*----------------------------------------------------------
program define EstPost_se, eclass
tempname b2 v2
mat `b2' = e(b)
mat `v2' = e(V)
est post `b2' `v2', noclear
end
*----------------------------------------------------------
program define GetEq, sclass
args ism isv eqlist varlist esamp
tempname B
local flag = 0
mat `B'= e(b)
local ename : coleq `B'
local fullist
tokenize `ename'
local fullist `1'
while "`2'" != "" {
if "`2'" != "`1'" {
local fullist "`fullist' `2'"
}
mac shift
}
if "`fullist'"=="_" {
local fullist
}
*---- Parse eqlist
if "`eqlist'" == "" {
local eqlist `fullist'
}
else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -