assetsDir: 'static',
parallel: false,
publicPath: './',
}
1. 基本原理事情的起因是,一直以来想写个自动筛选控制变量的命令,在查阅资料之余偶然间发现了这个开源项目。但是使用之后发现程序本身还有不少需要完善的地方,并且此项目已经很久没人更新了,因此,打算自己动手进行完善。在使用的过程中,根据自己的需求完善了部分内容。具体思路和代码如下:
想法很简单,直接遍历所有的控制变量集,通过tuples命令实现,下边简单介绍下改命祥旅升令的使用方式
sysuse auto.dta, claer // 导数数据 tuples weight length turn displacement , min(2) max(4) // 返回子集,其中每个子集包括2-4个元素
运行完程序之后,我们重点需要关注其返回值
dis "`ntuples'" // nutuples满足条件的子集个数 dis "`tuple1'" // 第一个子集 -- "`tuple`i''"调用第i个
运行完之后,我们可以发现,满足条件的子集共有11个,且第1个为turn displacement。
于是,我们可以将这些子集放入逐个进行回归。并通过一些条件语句,将满足条件的子集储存下来。最后即可得到满足所有条件的集合。同时,有些时候我镇虚们需要同时对多个方程进行限定,需对程序进行些许的改动。大致思路是:在多方程程序中,调用单方程的返回结果,并取交集,即可实现。
2. 完整代码
这里提供附带详细注释的,用于筛选控制变量的完整代码。大家在使用的过程中,可以将其复制到stata的do文件编辑器中,并保存为.ado格式即可自行进行调用。
第一个ado程序:对于单个方程进行筛选
/* 新增内容:1. 增加能让变量不显著的判定 2. 设置不用在意显著性和符号的控制变量集合 3. 支持分组回归 4. 支持因子变量和时间序列变量 有待补充: 1. 需要对多个变量的符号进行控制(如交互项、二次项等) 2. 计算速率优化 -- 只用计算系数可以不调用reg 3. 将核心变谨老量和显著性输入到一个参数中[]*/cap program drop select_vars // 删除缓存中的文件 program select_vars, byable(recall) rclass // 设定程序返回值类型为r-classversion 16.0 // 设定版本为stata 16syntax varlist(min = 2 fv ts) [if] [in], Control(varlist fv ts) MODel(string) /// [Must(varlist fv ts) min(int 1) max(int 10) Times(real 10) /// P_value(real 0.05) SYmbol(string) /// XSEcend(varlist fv ts max = 1) PSEcend(real 0.05) SYSEcend(string) /// Negative *] // 输入参数************* * 变量说明: * ************* * varlist -- 变量集 至少两个数值型(numeric)变量 * [if] [in] -- 可选条件 if &in * control -- 控制变量集 varlist形式 * model -- 回归模型 str * must -- 必有的变量 varlist形式 * min -- 最少子集数 int形式 默认为1 * max -- 最多子集数 int形式 默认为10 * time -- 多久显示一次进度条 默认为10% * p_value -- 核心解释变量临界P值 real number形式 默认为0.05 * symbol -- 核心解释变量符号 string形式 * xsecend -- 第二个需要关注的变量 * psecend -- 第二个变量的p值 * sysecend -- 第二个变量的符号 * negative -- 可选调节参数 选择时变量不显著 * fv -- factor variables * ts -- time-series operators************* * 预先处理: * ************* gettoken y x: varlist // 将varlist分为y(第一个)和x(剩余的) gettoken x_core x_other: x // 将x分为核心(x_core)和其他(x_other)qui tuples `control', min(`min') max(`max') // 设置控制变量为全集 * min -- 子集最少元素数 * max -- 子集最多元素数matrix results = J(`ntuples', 1, 0) // 生成`ntuples'行1列的0矩阵 matrix colnames results = "flag" // 定义列为flag local n 0 // 统计满足条件的方程数量 local con_list // 统计满足条件的控制变量集合 * 注意:negative并不影响二次项 -- 若需要二次项不显著,则不加二次项即可 if "`negative'" == ""{ local comp "<" // 正常情况下P值越小越好 } else{ local comp ">" // 反之则需要P值越大越好 } if ("`symbol'" == "" &"`sysecend'" == ""){ // 均不限定 local symbol_judge "1" // 不加符号限定恒为真 } else if("`symbol'" != "" &"`sysecend'" == "" ) { // 只限定核心解释 local symbol_judge "_b[`x_core'] `symbol' 0" // 否则需判定其与0之间的关系 } else if("`symbol'" == "" &"`sysecend'" != "") { // 只限定第二变量 local symbol_judge "_b[`xsecend'] `sysecend' 0" } else if("`symbol'" != "" &"`sysecend'" != ""){ local symbol_judge "_b[`x_core'] `symbol' 0 &_b[`xsecend'] `sysecend' 0" } if("`xsecend'" == ""){ // 若没有输入第二变量 local psecend_judge "1" // 恒为真 } else{ // local psecend_judge = "`p_sece' <`psecend'" // 这样不能读入p_sece会报错 local psecend_judge = "2 * ttail(e(df_r),abs(_b[`xsecend']/_se[`xsecend'])) <`psecend'" }marksample touse // 使用touse记录有效样本* >>>>>>主体开始 <<<<<<preserve // 暂时保存样本qui keep if `touse' // 只保存有效样本,且不显示 local j 1 forvalues i = 1/`ntuples'{ // `ntuples'返回全集的子集个数* 设置进度条 if(floor(`i'/`ntuples' * 100)/(`times') >= `j' | `i' == `ntuples'){ local percent = `j' * `times' // 记录百分比 if(`i' == `ntuples'){ local percent = 100 } dis "...`percent'%" _c // _c不换行 local j = `j' + 1 }local x_con "`tuple`i''" // 设置控制变量 qui `model' `y' `x_core' `xsecend' `x_other' `must' `x_con', `options'* 回归结果的分析 local p_core = 2 * ttail(e(df_r),abs(_b[`x_core']/_se[`x_core'])) // 统计P值 // 根据t值计算其对应的p值if(`p_core' `comp' `p_value' &`psecend_judge' &`symbol_judge'){ // 如果满足条件 local n = `n' + 1 // 满足条件的方程数量 + 1 local con_list = "`con_list'" + ", " + "`x_con'" // 添加符合的集合 matrix results[`i', 1] = 1 // 结果满足 } else{ matrix results[`i', 1] = 0 // 结果不满足 }} restore // 恢复原始样本* >>>>>>主体结束 <<<<<<local con_list = subinstr("`con_list'", ", ", "", 1) // 删除第一个", " local list = "`con_list'" // 存储控制变量集 local con_list: subinstr local con_list ", " "+", all // 将所有的逗号替换成 + local con_list: subinstr local con_list " " "-", all // 将所有的空格替换成 - local con_list: subinstr local con_list "+" " ", all // 将所有的加号替换成************* * 结果返回: * ************* * 矩阵的返回 return matrix sets = results // 返回结果矩阵* 值的返回 return scalar num_set = `n' // 返回满足条件的集合个数* 暂元返回 return local y = "`y'" // 返回被解释变量 return local x_core = "`x_core'" // 返回核心解释变量 return local list = "`list'" // 返回满足条件的控制变量集 -->用于展示 return local con_list = "`con_list'" // 返回满足条件的控制变量集 -->用于调用end
第二个ado程序:同时满足多方程
cap program drop select_multi program select_multi, rclass syntax anything [if] [in], [List]local equations = subinstr(subinstr(subinstr("`anything'","[","",1),"]","",.),"[","",.) * 程序效果: 将输入的 "[]" 中的内容用 "" 分割 * step 1. eq1 = subinstr("`anything'", "[", "", 1) -- 删除输入参数的第一个 "[" * step 2. eq2 = subinstr(`eq1', "]", "", .) -- 删除eq1中的所有的 "]" * step 3. eq3 = subinstr(`qe2', "[", "", .) -- 将eq2中所有的 "[" 替换为 "" local equations: list retokenize equations // 去掉多余空格 local eqnum = ustrlen("`equations'") - ustrlen(subinstr("`equations'", "", "", .)) + 1 * 方程数 = 分号数 + 1 = 有分号的长度 - 无分号的长度 + 1 tokenize "`equations'", parse("") // 将方程按照分号分割 其中第i个方程用 `i'表示 forvalues i = 1/`eqnum'{ // 遍历方程 local j = 2*`i' - 1 // 由于分号会占位,第2*i-1个位置为方程位置 local equation = "``j''" // j = 1 时 `j' = 1 -- 暂元的引用 ``j'' = `1' 表示第一个方程 dis "方程`i'进度:" _c select_vars `equation' // 执行子程序 if(`i' == 1){ local com_lists = r(con_list) // 满足条件的集合 } else{ local con_list = r(con_list) // 结果存放到con_list local com_lists: list com_lists &con_list // 取交集 } local solunum = r(num_set) // 统计满足条件的个数 dis " -- 有`solunum'个集合" } local re_lists = "`com_lists'" local com_lists :subinstr local com_lists " " ", ", all local com_lists :subinstr local com_lists "-" " ", all local listnum = ustrlen("`com_lists'") - ustrlen(subinstr("`com_lists'", ",", "", .)) + 1 if ("`list'" != ""){ // 需要展示结果 dis "满足所欲条件的结果包括:" tokenize "`com_lists'", parse(",") // 按逗号分割 forvalues i = 1/`listnum'{ local j = 2*`i' - 1 dis "solution`i': ``j''" // 展示第i个结果 } } return scalar lists_num = `listnum' // 满足条件的集合数 return local list = "`re_lists'" // 满足条件的集合 -- 用于返回 return local com_lists = "`com_lists'" // 满足条件的集合 -- 用于展示 end
第三个do文件:程序调用样例
do "select_vars.ado" // 调用select_vars文件 do "select_multi.ado" // 调用select_multi文件sysuse auto, clear // 导入数据 cls // 清屏local y price // 被解释变量 local x rep78 // 解释变量local x_con "turn trunk weight headroom" // 控制变量 local x_must "i.foreign" // 必有变量* 单方程筛选 select_vars price rep78 , c(`x_con') mod(reg) m(`x_must') n p(0.5) t(25) min(2) symbol(">") r /* 其中price为y,rep78为所关心的核心x c -- 需要筛选的控制变量 mod -- 选择普通回归模型reg命令进行回归 m -- 必须存在的控制变量 n -- p值需要大于临界值 p -- p的临界值为0.05 t -- 进度条间隔为25% min -- 可选控制变量至少得有2个 symbol -- 核心解释变量的系数需大于0 r -- 返回稳健性标准误 */ return list // 返回列表 dis "`r(list)'" // 展示满足条件的集合* 多方程筛选 select_multi [price length, c(`x_con') mod(reg) m(`x_must') n symbol(<) min(2) r] /// [price rep78, c(`x_con') mod(reg) m(`x_must') n min(2) r] // "[]" 中为需要限定的单方程模型 "///" 表示换行 return list dis "`r(com_lists)'" // 展示满足条件的集合
3. 使用 *** 作
注意:如果自己懂得外部命令的手动安装,以及路径设置的基本知识,可以自行发挥。如果不是很清楚这方面的知识,请严格安装以下要求进行调用,为保证后续样例代码能运行,需将ado文件保存为样例名,并和样例文件放在同一个文件夹下。
1.打开stata并创建新的do文件
创建空白do文件
2.将代码另存为文件
将代码另存为
需要注意的是,对于第1和2个程序,文件名(右边红框)需和program后的程序名(左边红框)相同。对于第3个程序,另存为什么名字则无所谓。
3.保存完成:我们能够得到这样的三个文件
保存完成
注意:三个文件需要在同一个文件夹下;并且test是do文件,另外两个为ado文件
4.运行test文件(也就是提供的程序3)
输出结果演示
单方程变量的结果存放在r(list)暂元中、多方程存放在r(com_lists)中,其中使用,对满足条件的子集进行分割。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)