1. 把"多元"两个字先想透:Stata 的 reg 到底在解一个什么问题
很多人第一次在 Stata 里敲下reg y x,看到 P>|t| 小于 0.05 就松了一口气,截图留档收工。等到加上第二个控制变量,斜率一下子少了一半,甚至符号翻过来,人就开始慌了——到底哪个结果能用?这种慌张的根源不在 Stata,而在于没有想明白多元回归分析这件事本身在干什么。它不是"多塞几个变量"这么简单,它要回答的是一个更苛刻的问题:在把其他已知因素按住不动的前提下,某个变量和因变量之间还剩下多少关系。
Stata 在这件事上给的是最朴素也最可靠的工具。它不会替你做模型设定,不会提醒你遗漏了什么变量,也不会告诉你某个系数为什么长得这么奇怪。它只负责把最小二乘法的解算出来,把方差分解表、系数表、拟合优度整整齐齐摆在屏幕上。剩下的事,全在敲命令的人手里。所以这篇东西的重点不是罗列命令,而是把从数据整理到结果解释、从诊断到导出这一整条链路上,那些教程里往往一笔带过、实战中却天天要面对的细节讲清楚。
下面的内容适合三类人:刚学完计量课、第一次真正拿数据上手的学生;需要用 Stata 出分析报告、但被审稿人或老板追问过"这个系数怎么解释"的研究人员;以及已经会用reg但总觉得结果不太踏实的从业者。全文以多元回归分析为主线,穿插数据清洗、异常值处理、亚组分析、结果导出这些绕不开的配套动作。网状 Meta 分析也好,面板回归也好,底层的那套"设定—估计—诊断—解释—复现"的流程是完全相通的,把这一套吃透,换模型只是换命令。
1.1 从一元到多元,多出来的那部分到底管什么
一元回归里,斜率是"x 变动一单位,y 平均变动多少",这个解释成立的前提是——所有影响 y 的其他因素都和 x 无关,或者干脆不存在。现实里这个前提基本不成立。举个具体的例子:分析某类商品的销量和价格,一元回归跑出来价格系数是正数,看着很反直觉。原因很简单,天气、促销档期、节假日这些变量既影响价格(旺季加价)又影响销量(旺季卖得多),它们的作用全被塞进了价格系数里,把它污染了。这就是遗漏变量偏误。
多元回归的做法是把这些"捣乱"的变量显式地放进模型。此时每个系数的含义变成:在其他自变量保持不变的条件下,该变量每变动一个单位,因变量的平均变动量。这句话里的"保持不变"是多元回归的灵魂,也是它和一元回归唯一的本质区别。技术上,最小二乘法在做的事情是让残差平方和最小,几何上相当于把因变量向量投影到所有自变量张成的那个平面上。自变量之间哪怕高度相关,只要不完全共线,投影依然唯一,只是这个投影对数据的微小扰动会越来越敏感——这就是后面要讲的共线性和稳健性的来源。理解了这一点,再看诊断部分就不会觉得那些检验是多余的仪式,它们都是在回答同一个问题:这个投影到底稳不稳。
1.2 Stata 命令语法的那套通用骨架
Stata 命令的语法结构高度统一,记住一次,后面所有命令都能套:
[by varlist:] command [varlist] [=exp] [if] [in] [weight] [, options]拿回归来说,reg是regress的合法缩写,惯例是把因变量写在最前面,自变量跟在后面,中间用空格分开。这跟很多软件的公式写法(y ~ x1 + x2)不一样,刚开始容易写反,写反了 Stata 不会报错,它会老老实实给你算出一个完全不同的模型——因为它在拟合"第一个变量被后面那些变量解释"。这也是新手交报告时结果对不上的高频原因之一,写完命令回头看一眼变量顺序,比事后排查省事得多。
if和in这两个限定词值得单独提一句。if是逻辑条件,in是行号范围。做亚组分析、剔除极端值、限定时间窗口,全靠if。它不改变模型结构,只改变参与估计的样本,所以每一次加if都要意识到样本量在变,系数的可比性也在变。
1.3 有些时候不该用多元回归
模型形式要和数据结构匹配,这句话我说过很多遍。因变量是 0/1 二值,用reg得到的预测值可能超出 0 到 1 的范围,标准误也不对,应该换成logit或probit。因变量是计数(比如某段时间内的事件次数),poisson或nbreg更合适。同一批个体被反复观测,那就是面板结构,得先用xtset声明,再上xtreg。
还有一种情况是内生性——某个自变量和误差项相关,可能是因为遗漏了变量,也可能是因为反向因果。这时的正解是找工具变量,用ivregress或者外部的ivreg2,而不是硬扛。我不建议把"用了更复杂的模型"当成水平高低的标志,选模型的唯一标准是它和不匹配数据结构的代价相比,哪个更划算。一个设定干净的 OLS,说服力往往强过一个塞满花哨选项但逻辑混乱的模型。
2. 建模之前的那半小时:数据整理决定你后面三天的返工量
我见过太多人拿到数据直接reg,跑完发现结果不对再回头查数据,来回折腾。真正的顺序应该反过来:先花二十分钟把数据的家底摸清楚,后面能省下大把时间。Stata 里摸家底的三个命令是describe、codebook、summarize,配合起来基本能把一个陌生数据集看透。describe告诉你有哪些变量、什么类型、什么标签;codebook会具体展示每个变量的分布、唯一值个数和缺失情况;summarize, detail则给出分位数、偏度、峰度这些分布形状信息。
2.1 变量类型分不清,后面全是坑
建模前必须把每个变量归到下面几类之一,因为它们的处理方式和解释方式完全不同:
| 变量类型 | 典型例子 | Stata 里的处理 | 回归中的角色 |
|---|---|---|---|
| 连续变量 | 收入、年龄、面积 | 直接用,必要时取对数 | 系数解释为边际效应 |
| 二值变量 | 是否女性、是否处理组 | i.或事先gen成 0/1 | 相对参照组的差异 |
| 多分类变量 | 行业、地区、学历档 | i.var因子变量 | 每个类别对参照组 |
| 有序分类变量 | 满意度 1-5 级 | i.var,或当连续用 | 视假设而定 |
| 字符串变量 | 姓名、编号 | encode或destring | 一般不入模型 |
多分类变量最容易出问题。有人图省事,把"行业代码 1 到 20"当连续变量塞进模型,得到的结果是"行业代码每增加 1,因变量平均变动多少"——这句话本身没有任何业务含义,因为行业代码的大小顺序是人为编的。正确做法是用i.industry生成哑变量,让每个行业和参照行业比。
字符串转数值也要注意encode和destring的区别:destring是把"123"这种长得像数字的字符串真正转成数值 123;encode是把"北京""上海"这种纯文本映射成 1、2、3,并附加一层值标签。用错了,要么转换失败,要么把顺序信息彻底丢失。
2.2 缺失值的代价比你想象中大
Stata 把缺失值当作一个极大的正数(.表示数值缺失),所以对它求和、求最大值的操作会全部变成缺失。这是很多人第一次踩的坑。查缺失用misstable summarize或者外部命令mdesc,一行就能看到每个变量的缺失数量和比例。
处理方法要分情况。缺失比例很低(比如低于 5%)而且看起来是随机丢的,直接删除观测是最省事的选择,代价是样本量减少。缺失比例高,或者缺失本身和因变量有关(比如收入高的人更不愿意填收入),直接删就会带来选择偏误,这时要考虑多重插补(mi系列命令)或者其他填补策略。我个人的判断标准是:先把"有缺失"和"无缺失"两组的关键变量均值对比一下,如果差异明显,就别删,老老实实做插补并在报告里说明。
2.3 最大值最小值:异常值筛查的第一道网
热词里有人搜"stata 最大值最小值命令",说明很多人卡在这一步。这里有个必须分清的细节:egen的max()和min()作用是取整列的极值,然后把同一个数字填到每一行;而rowmax()和rowmin()才是取每一行内部几个变量的极值。
* 整列极值:所有观测得到的同一个数 egen max_income = max(income) * 每一行的极值:逐行比较三个变量 egen row_max = rowmax(x1 x2 x3)把这两个搞混,会得到看起来"很正常"但其实完全错误的变量。我在帮别人看代码时,最常见的错误之一就是本意想做逐行最大值,却写成了egen xxx = max(a b c)。
筛查异常值的标准动作是先跑分布:
summarize income, detail输出里的 Min、Max、1%、99% 分位数、偏度和峰度都值得看。如果 1% 分位数是 3000、最大值却是 99999999,那基本可以确定存在录入错误或者单位不统一(比如有人填了分,有人填了元)。处理选项按稳妥程度排序:先核原始记录,确认是错误就修正或删除;确认是真实的极端值,就考虑缩尾(winsor2,需要ssc install)、截尾,或者用对异常值不敏感的稳健回归rreg、分位数回归qreg。直接删掉真实存在的极端值,是在用制造偏误的方式掩盖问题,报告里也很难自圆其说。
2.4 标签与 do 文件:给三个月后的自己留条路
label variable给变量加说明,label define给取值加含义,这些看起来是可选项,其实是必需品。一个月后你看到b3这个变量名,大概率想不起来它代表什么。更关键的是,给变量加标签之后,esttab导出的表格会自动带上标签,省去手动改表的功夫。
do 文件要从头到尾能跑通,这是底线。我习惯把它分成四段:环境设置(clear all、set more off、版本声明)、数据准备、分析、导出。每次改动都在 do 文件里改,而不是在命令行里敲。命令行敲出来的结果,第二次想复现的时候就得靠回忆,这在需要交付的场景里非常危险。
3. 第一遍 reg 跑通之后:那张输出表每一行都该看得懂
模型跑出来之后,屏幕上那张表信息量其实很大,但很多人只看 P>|t| 那一列。我们把它拆开看。
3.1 命令与几个真正有用的选项
reg ln_wage edu exper exper2, vce(robust)vce(robust)是最常用的选项,它不改变系数,只改变标准误的计算方式,让结果在存在异方差时依然可信。beta选项会额外输出标准化系数,用于比较不同量纲变量的相对重要性。level(90)可以把置信区间从默认的 95% 改成 90%。noconstant是强制过原点,除非你非常确定回归线必须经过原点,否则不要加——强行去掉截距会让所有系数的含义发生改变。
3.2 方差分解表:先判断模型整体站不站得住
表的上半部分是:
| 指标 | 含义 | 什么时候要警惕 |
|---|---|---|
| Number of obs | 实际参与估计的样本量 | 和你预期差很多,说明缺失或条件筛掉了样本 |
| F(k, n-k-1) | 模型整体显著性检验 | 不显著说明所有自变量加起来也解释不了 y |
| Prob > F | F 检验的 p 值 | 大于 0.05 时,单个系数再显著也要谨慎 |
| R-squared | 解释的方差比例 | 跨数据集比较没有意义 |
| Adj R-squared | 自由度调整后的 R² | 比较嵌套模型时看这个,不看 R² |
| Root MSE | 残差的标准误 | 量纲和因变量一致,越小拟合越好 |
F 检验的原假设是"所有自变量的系数同时为零",它检验的是整组变量,而不是某一个。这一点常被误解:F 检验不显著但你关心的那个变量 t 检验显著,这种情况说明模型整体很弱,那个显著结果很可能是不稳定样本下的偶发,不要急着当结论用。
Adj R-squared 和 R-squared 的差别在于前者惩罚了参数个数。你每往模型里加一个变量,R² 一定不会下降,哪怕加的是随机数,这就让 R² 在模型比较里失去了意义。Adj R² 会下降,所以"加变量后 R² 上升"不构成保留该变量的理由。Root MSE 常被忽略,但它在比较同一因变量、不同设定的模型时非常直观。
3.3 系数表:五列信息各管什么
下半部分每一行对应一个自变量,列分别是 Coef.、Std. Err.、t、P>|t|、[95% Conf. Interval]。
Coef.是点估计值,量纲和因变量、自变量的量纲绑定,不能直接横向比较大小——除非做了标准化。
Std. Err.是估计的不确定程度。样本量越大、自变量变异越大、共线性越低,标准误越小。看到标准误比系数还大,说明这个估计非常不稳。
t 值就是 Coef. 除以 Std. Err.,Stata 帮你算好了。它不是独立信息,而是前两列的比值。
P>|t|是原假设"该系数为零"成立时,观测到当前或更极端 t 值的概率。它受样本量影响极大:样本几万的时候,一个业务上毫无意义的微小系数也可能显著;样本只有几十的时候,真实的大效应也可能不显著。所以我不建议把 0.05 当成生死线,把它当作一个连续的证据强度更合理。
置信区间和 p 值是一体两面。区间跨过 0 等价于 p 大于 0.05。我更愿意先看区间:它直接告诉你效应可能的范围。样本小的时候经常出现 p 小于 0.05 但区间宽得离谱(比如系数 0.5,区间 [0.02, 0.98])的情况,这时候说"显著的正向影响"是自欺欺人,实际含义是"方向可能是正的,也可能接近零"。
3.4 输出表里没有的东西,才是真正的风险点
Stata 默认不会打印 VIF,不会做异方差检验,不会标记强影响点。它给的是一个"在理想假设全成立时"的结果。这些假设是否成立,得你自己去查。下一节就按排查顺序把它们一个个过一遍。顺序上我的习惯是:先看分布和异常值(最基础,问题最容易发现),再看函数形式(设定错了,后面全白做),然后查共线性(影响系数稳定性),最后处理异方差(影响标准误和推断)。
4. 系数怎么讲成人话:连续、哑变量、交互项三条不同的解释路径
拿到系数不会解释,等于模型白跑。不同类型的变量,解释路径完全不同,而且这里的错误往往比技术错误更致命,因为它直接影响结论的可信度。
4.1 连续变量:注意量纲和对数变换
最基础的情形:y = 3.2 + 0.8 * x,x 每增加 1 个单位,y 平均增加 0.8 个单位,前提是其他变量不变。要注意 x 的单位——如果 x 是"万元"而你以为它是"元",这个 0.8 的含义就差了一万倍。
对数变换的三种组合必须分清楚,这是报告里出错最多的地方:
| 因变量 y | 自变量 x | 系数 b 的含义 | 术语 |
|---|---|---|---|
| 原始值 | 原始值 | x 增 1 单位,y 增 b 单位 | 水平效应 |
| ln(y) | 原始值 | x 增 1 单位,y 大约变动 100b% | 半弹性 |
| 原始值 | ln(x) | x 增 1%,y 增 b/100 单位 | 半弹性 |
| ln(y) | ln(x) | x 增 1%,y 增 b% | 弹性 |
严格来说,ln(y)对x求导得到的是比例变化b,转换成百分比更精确的公式是100*(exp(b)-1)。当 b 比较小(比如小于 0.1)时,100b和精确值差别不大,可以近似;但 b 比较大(比如 0.5 以上)的时候,用100b会明显高估,这时候老老实实用公式算。
4.2 哑变量和参照组:别忘了陷阱和基准
多分类变量用因子变量语法i.处理:
reg wage edu i.region i.industryStata 会自动把每个分类变量的第一个取值作为参照组,其余类别生成哑变量。想要指定参照组,用ib3.region表示以 region 等于 3 的那一类为基准。系数解释是"相对于参照组,该类别的因变量平均高出(或低于)多少"。
哑变量陷阱值得单独说:如果你手动tabulate region, generate(d)生成了全部 5 个哑变量,然后一起放进模型,会和截距项完全共线,Stata 会自动丢掉一个并给出提示。这时候丢掉的是哪一个取决于变量进入的顺序,可能导致你根本不知道当前的基准是谁。所以我更推荐直接用i.region,让 Stata 管理这件事。
还有个实际问题:参照组的选择会改变所有系数的数值,但不会改变模型整体的拟合和统计推断。报告时一定要写明基准是哪一类,否则读者无法理解系数的含义。
4.3 交互项:不要只看交互项系数就下结论
交互项用来回答"x 对 y 的影响在不同群体里是否不同",这也是亚组分析最常见的做法。语法上,#表示只有交互项,##表示主效应加交互项:
reg wage c.edu##i.femalec.edu##i.female展开后等于edu+i.female+edu#i.female三项。如果只写c.edu#i.female,模型里就没有性别的主效应,解释会变得别扭,一般不推荐。
关键的坑在这里:交互项的系数显著,只能说明"两组斜率存在差异",不能直接说明"某一组里 x 有显著影响"。正确的做法是用margins:
margins female, dydx(edu) marginsplot第一行命令会给出两组各自的教育回报率及其标准误、置信区间,这才是可以直接报告的数字。marginsplot 把结果画成图,比一堆数字更直观。我见过不少论文在交互项显著之后,只报告了分组回归的系数就下结论,逻辑上是不完整的。
4.4 标准化系数:只在同一个模型内部有意义
当自变量量纲相差悬殊(比如年龄是几十,GDP 是几万亿),直接比较系数大小没有意义。加beta选项可以得到标准化系数,它表示自变量变动一个标准差,因变量变动多少个标准差。用于同一模型内的相对重要性排序是合适的,跨模型比较就要小心,因为样本和变量集合一变,标准差也变了。
5. 诊断别只做一种:共线性、异方差、异常值、函数形式的排查顺序
我把诊断分成四块,按我自己的排查顺序展开。顺序不是绝对的,但这个顺序的好处是:前面的问题被发现并处理掉,后面的检验才更有意义。
5.1 多重共线性:VIF 高不一定就要删变量
reg y x1 x2 x3 estat vif输出里每个变量一个 VIF 值,还有 1/VIF。经验阈值通常说 VIF 大于 10 提示严重共线,保守一点用 5。但这里有个必须讲清楚的逻辑:共线性本身不会让系数估计产生偏误,它只会让系数的标准误变大、估计变得不稳定。也就是说,共线性高的时候,你更容易得到不显著的结果,但你得到的显著结果依然是可信的方向。
所以看到高 VIF 不要条件反射地删变量。先问两个问题:这个变量是不是理论上必须控制的?删了它会不会引入遗漏变量偏误?如果它重要,那宁可接受较大的标准误,也要保留。只有在两个变量测量的是几乎同一个东西(比如"总收入"和"工资收入"),才有充分理由合并或删除其一。其他可选的处理方式包括主成分回归、增大样本量、或者用岭回归这类带偏但方差更小的估计方法。
顺便提醒一句:estat vif只能紧跟reg之后使用,如果中间插了别的估计命令,会提示找不到结果。另外,只要模型里包含因子变量或者交互项,estat vif会为每个展开后的项都报一个值,解读时要留意。
5.2 异方差:先看图,再做检验,最后决定要不要改标准误
最直观的检查是画残差图:
reg y x1 x2 rvfplotrvfplot画的是残差对拟合值,如果点云呈现喇叭形(拟合值越大,残差越分散),基本可以确认存在异方差。再补一个正式检验:
estat hettest estat imtest, whiteestat hettest是 Breusch-Pagan 类的检验,estat imtest, white是 White 检验。原假设都是"同方差"。p 值小于 0.05 就拒绝同方差假设。
处理方式上,我的默认选择是直接把vce(robust)加进模型,而不是去做加权最小二乘(WLS)。原因很简单:稳健标准误不需要你正确设定异方差的具体形式,代价只是标准误可能略大一点点,换来的是推断的可靠性。WLS 需要你知道方差和某个变量的函数关系,猜错了反而更糟。
聚类标准误是另一个场景。同一家公司多个年度、同一所学校多个学生,这类数据里误差项在组内相关,必须用vce(cluster id)。判断标准是:如果你的观测可以自然分组,并且在组内不独立,就该用聚类。注意聚类数量太少(比如少于 30 到 40 组)时,标准误本身也不可靠,这时要用 bootstrap 或者野生聚类 bootstrap 之类的替代方案。
5.3 异常值和强影响点:分清"离群"和"有影响力"
异常值有两个维度:因变量方向离群(残差大)和自变量方向离群(杠杆高)。Stata 里可以这样看:
reg y x1 x2 predict resid, residuals predict lev, hat predict cooksd, cooksd lvr2plot dfbeta阈值方面的经验规则:杠杆值大于2k/n(k 是自变量个数,n 是样本量)值得关注;CooksD 大于4/n就属于强影响点。lvr2plot画的杠杆-残差平方图能一眼看出右上角那几个点——它们同时具备高杠杆和大残差,对系数的影响最大。
发现强影响点之后的处理流程,我建议按这个顺序:先核对原始数据是不是录入错误,这一步能解决相当一部分问题;确认数据无误后,判断这个观测是否属于研究总体(比如研究普通企业却混进了一家巨型央企);如果确实属于总体内,就做敏感性分析——删掉它们重跑一遍,看结论是否变化。如果结论对几个点这么敏感,那本身就是一个需要如实报告的发现,而不是藏起来。
5.4 函数形式:设定错了,后面全白做
诊断顺序里我把函数形式放在靠前的位置,因为它是最容易被忽略、后果又最严重的一类问题。检验手段有:
estat ovtest // Ramsey RESET 检验 linktest // 检查是否需要增加非线性项estat ovtest检验的是模型是否需要加入拟合值的幂次项,显著就意味着可能存在遗漏的非线性关系。linktest会重新跑一个包含拟合值和拟合值平方的模型,如果平方项显著,说明线性设定不够。
可视化上,avplots给出每个自变量对因变量的偏回归图,rvpplot画残差对各自变量。图上如果呈现明显的弯曲形状(比如 U 形),说明该变量可能需要平方项或者取对数。另外,残差正态性的检验(sktest、swilk)在小样本里值得做,但在大样本里由于中心极限定理,正态性对系数推断的影响很有限,不要为了这个折腾太久。
6. 稳健性与亚组分析:让结论经得起追问
模型跑通、诊断过关,只能说技术上没问题。真正的考验是别人问"换个指标会不会变""换个样本会不会变""换个时间段会不会变"。
6.1 嵌套模型对比与信息准则
比较嵌套模型的标准做法是存结果再对比:
reg y x1 x2 estimates store m1 reg y x1 x2 x3 x4 estimates store m2 lrtest m1 m2 estat iclrtest做的是似然比检验,原假设是"受限模型(少的那个)足够"。estat ic给出 AIC 和 BIC,适用于比较非嵌套模型。要格外注意:AIC/BIC 和 R² 不是一回事,前者偏向预测能力,后者偏向解释力,报告里选哪个要看你的研究目的。
6.2 亚组分析:分组回归不能直接比较系数
这是审稿意见里出现频率极高的一条。很多人做了分样本回归,看到一组显著、一组不显著,就得出"该效应只存在于某一组"的结论。这个推理是错的——一组显著一组不显著,可能只是因为一组的样本量小、标准误大,两组的系数差异在统计上并不显著。
正确做法有两条路。推荐的是交互项法,前面讲过,用margins给出两组各自的边际效应,用交互项本身的检验判断差异。另一条路是分样本回归后做组间系数差异检验:
reg y x controls if group == 1 estimates store g1 reg y x controls if group == 0 estimates store g2 suest g1 g2 test [g1_mean]x = [g2_mean]xsuest把两个独立估计的结果合并起来做联合检验。有几个注意点:如果模型里用了vce(robust),suest的兼容性要确认;两个子样本里必须存在同名但互不重叠的变量,所以一般需要先在两个子样本里各生成一份变量再合并,操作上略显繁琐。所以我日常更倾向交互项法,代码短、解读清晰、也更容易画图。
6.3 换指标、换样本、换模型:稳健性三件套
稳健性检验不是走过场,它的目的是说明"结论不是因为某个特定选择才出现的"。常用的三类操作:
换指标:核心自变量有多个测量方式,比如"企业规模"可以用员工数、也可以用资产总额,两个都试一遍。因变量同理,比如"盈利能力"可以用总资产收益率也可以用净资产收益率。
换样本:剔除极端年份、剔除特定地区、剔除规模最大或最小的 1%,看结论是否稳定。如果某个子样本里结论完全反转,那要深入分析而不是回避。
换模型:OLS 换成稳健回归、分位数回归,或者对二值因变量换成 logit。模型换了结论还在,说服力就上一个台阶。
这三类做下来,通常需要三到五张表格。用esttab并排输出,比手工整理效率高得多。
6.4 逐步回归:能不用就不用
stepwise看起来很方便,自动帮你选变量。但它有个致命问题:最终模型是在数据上反复筛选出来的,此时计算出来的 p 值、置信区间都不再具有名义上的统计意义,因为它没有考虑"搜索"这个动作带来的多重比较问题。在预测任务里,它作为特征筛选工具尚可;在需要解释系数、做因果推断的场景里,我不建议使用。宁可根据理论和文献先定好变量集合,再用数据验证。
7. 结果导出与工程化:让三个月后的自己能复现
分析做完,最后一公里是交付。手工把系数敲进 Word 出错率高、改动成本大,用命令导出才是正路。
7.1 esttab 基础用法
先安装:
ssc install estout, replace然后:
eststo clear reg ln_wage edu exper exper2 i.female, vce(robust) eststo m1 reg ln_wage edu exper exper2 i.female i.region, vce(robust) eststo m2 esttab m1 m2 using "regression_table.rtf", replace /// b(3) se(3) star(* 0.10 ** 0.05 *** 0.01) /// r2 ar2 nogap label几个参数值得说明:b(3)控制系数保留三位小数,se(3)控制标准误位数,star()定义显著性星号阈值,nogap去掉模型之间的空行让表格更紧凑,label用变量标签而不是变量名。把结果存成.rtf的好处是可以直接用 Word 打开,格式基本可编辑。
7.2 并排输出的实用技巧
多模型并排时,几组选项经常一起用:
keep()只保留关心的变量,把控制变量的系数藏起来,indicate()则可以把一组变量合并成一行显示"已控制"mtitles("模型1" "模型2")自定义表头order()调整变量出现顺序,把核心变量放在最前面stats(N r2 ar2, labels("样本量" "R²" "调整R²"))控制底部报告哪些统计量drop(*.region)剔除某一组展开的哑变量
如果团队里习惯用outreg2,它的用法类似,outreg2 using file.doc, replace ctitle(模型1),第一步用replace,后续追加不加该选项,它会自动把新模型加到同一张表里。
7.3 do 文件的分层结构
我给 do 文件定过一个模板,用到现在比较顺手:00_master.do负责依次调用其他文件,01_clean.do做数据清洗和变量构造,02_analysis.do跑模型,03_export.do导表。每一层都从原始数据开始跑,中间文件用save落地,这样任何一步出错都能快速定位到源头而不是从头再来。
还有两个细节容易被忽略:一是版本声明,Stata 从 11 版引入因子变量语法,不同版本对某些命令的支持也不同,在 do 文件开头写version 16这类声明,能避免换机器后结果不一致;二是可重复性,如果分析里用到随机过程(bootstrap、模拟、插补),一定要写set seed,否则第二次跑出来的数字就不一样了。
8. 那些让人抓狂的报错:r(XXX) 背后的真实原因
Stata 的报错信息以r(数字)结尾,新手看到一串数字往往直接懵。其实常见的就是那么几种。
8.1 高频错误码对照
| 错误码 | 提示含义 | 常见真实原因 | 排查方向 |
|---|---|---|---|
| r(111) | variable not found | 变量名拼错或还没生成 | describe看变量清单 |
| r(109) | type mismatch | 字符串参与了数值运算 | 用destring或encode转换 |
| r(198) | invalid syntax | 逗号位置、括号、选项拼写有问题 | 拆开命令逐段试 |
| r(110) | already defined | 重复定义变量或标签 | 先drop或换变量名 |
| r(2000) | no observations | if条件把所有样本筛掉了 | 去掉if试跑,检查条件逻辑 |
| r(2001) | insufficient observations | 样本量小于参数个数 | 减少变量或扩大样本 |
| r(459) | not sorted | 用了by但数据没排序 | 改用bysort一条命令搞定 |
| r(601) | file not found | 路径写错或用错工作目录 | 用pwd和cd确认 |
8.2 字符串与数字的转换坑
类型不匹配是最隐蔽的一类问题,因为 Stata 只在真正用到的时候才报错。比如某个"收入"变量在导入时被识别成字符串,summarize能用(它会给个提示但能跑),一到reg就直接r(109)。
describe income destring income, replace如果报contains nonnumeric characters,说明里面混了文字或者"未知""缺失"这类标记,先list income if missing(real(income))找出这些观测,处理完再转。
encode和destring的取舍前面提过,这里再补一句实践建议:只有当你确实需要保留文本信息的时候才用encode,纯粹做数值运算就直接destring。
8.3 因子变量语法的误用
i.、c.、#、##这套语法很强大,但用错的地方也不少。i.group表示把 group 当作分类变量;c.age明确按连续变量处理(在有歧义的地方写出来更安全);c.age#c.age是交互项,也常用来自动生成平方项:
reg y c.age##c.age i.region这一句同时包含 age、age 的平方、region 哑变量,等价于手工生成age2 = age^2后再回归,但写起来干净得多。另外b0.、ib.、o.这几个前缀分别表示"把某类别设为基准"、"指定基准类别"、"省略该类别",处理共线或者调整基准时用得上,出报告前值得花十分钟熟悉。
8.4 模型之间样本量对不上
对比两个模型的系数时,如果参与估计的样本悄然变了,比较就不成立。样本变化的原因通常有三个:if条件不同、缺失值分布不同、共线性导致变量被自动剔除。第三个最隐蔽——模型里加了一个和已有变量高度共线的变量,Stata 会静默丢掉其中一个,样本量可能不变但模型已经不是你以为的那个了。
排查用这两个命令:
reg y x1 x2 x3 count if e(sample)e(sample)标记的是实际参与估计的观测,用count数一下就知道样本量。用并排表格导出时,把N一起报出来,也是让审稿人放心的一个细节。
我自己跑了这么多年回归,最后固定下来的习惯是这样:每次分析都先跑一遍最"素"的模型,只有核心自变量和因变量,把系数记在旁边做个参照;然后逐步加入控制变量,每加一次就看一眼核心系数动了多少。如果加了某个变量之后系数剧烈变化,那这个变量就值得单独讨论,它往往揭示了重要的机制,而不是需要被"修正"的干扰。参数稳定、方向一致,才敢往报告里写。至于那些被删掉的异常值、被换掉的时间窗口、被尝试过的各种设定,都留在 do 文件里,谁知道哪天审稿人就会问起其中某一个。