描述性统计:让审稿人"看见"你的数据
summarize / tabstat / bysort 分组、相关系数矩阵 pwcorr、estpost + esttab 一键导出三线表到 Word/Excel、histogram / kdensity 分布图、以及贯穿始终的 label 标签系统——Table 1 是一篇论文的"门面"。
estout / esttab、estpost;基础 summarize、pwcorr、tabstat、kdensity)。01 为什么 Table 1 是论文的门面
任何一篇实证论文的第一张表,几乎都是描述性统计表(Descriptive Statistics),通常被称为 Table 1。它告诉审稿人三件事:(1) 你的样本是什么(观测数、时间跨度、行业覆盖);(2) 每个变量的分布长什么样(均值、标准差、分位数);(3) 处理组与控制组在关键协变量上是否平衡(balance check)。一张写得好的 Table 1,能让审稿人在 30 秒内判断"这篇数据靠不靠谱"。
经济学直觉上,描述性统计本身不识别因果,但它能揭示问题:如果你的核心解释变量 $x$ 标准差极小,那它就不可能显著;如果处理组的企业规模比控制组大 10 倍,那后续不控制 firm size 就一定会有偏。Table 1 是你给自己写的"数据体检报告"。
02 summarize / tabstat:单变量分布
Stata 里最基础的两个命令:summarize(简写 sum)给出 N、mean、sd、min、max;加上 , detail 给出完整分位数(p1、p50、p99)。tabstat 是更灵活的版本,可以自定义要报告哪些统计量。
偏度(skewness)告诉你分布是左偏还是右偏——右偏意味着均值大于中位数,正是我们做对数变换的依据。峰度(kurtosis)> 3 说明比正态分布"厚尾",极端值更常见。
*--------------------------------------------------------------*
* 02-summarize-tabstat.do
*--------------------------------------------------------------*
sysuse nlsw88, clear
* 1) 基础 summarize
summarize wage tenure ttl_exp
* 2) detail:给出完整分位数与偏度峰度
summarize wage, detail
* 3) tabstat:自定义要报告的统计量
* statistics() 可填:mean sd p50 p25 p75 min max skewness kurtosis
tabstat wage tenure ttl_exp, ///
statistics(n mean sd p50 min max) columns(statistics)
* 4) 按年份分组的 tabstat(面板里常用)
* tabstat wage tenure, by(year) statistics(mean sd) columns(statistics)
03 标签系统:label variable / label define
描述性统计和后续导出表格能否"看得懂",完全取决于你有没有给变量打标签。这一步在 01 数据清洗页已经埋过伏笔,这里展开讲。Stata 的标签分两类:
- 变量标签(variable label):描述一个变量的含义,出现在
describe、esttab、outreg2输出的"Variable"列。 - 值标签(value label):把 0/1 翻译成"否/是",让
tab、esttab显示文字而不是数字。
*--------------------------------------------------------------*
* 03-label-system.do
*--------------------------------------------------------------*
sysuse nlsw88, clear
* 1) 变量标签:一句话写清楚
label variable wage "小时工资 (USD)"
label variable tenure "在当前雇主任职年限"
label variable ttl_exp "总工作经验 (年)"
label variable collgrad "是否大学毕业"
label variable south "是否居住在南部"
* 2) 值标签:定义一次,反复用
* label define 名字 数字 "文字" [数字 "文字" ...]
label define yesno_lbl 0 "No" 1 "Yes"
* 把标签贴到变量上
label values collgrad south yesno_lbl
* 3) 看效果
describe wage tenure collgrad
tab collgrad
tab south
estpost tabstat 与 esttab 都会自动读取变量标签作为行名。如果你在导出 Table 1 之前没打标签,导出的 Word 表里就会出现"wage""ttl_exp"这种无人能懂的代码,事后再手改 Word 是噩梦。
04 分组统计:bysort 与 bys 速记
面板数据里,"按年份看均值变化"、"按行业看差异"是描述性统计的高频操作。Stata 里 bysort 分组变量: 命令(可简写为 bys)就是这个用途。
*--------------------------------------------------------------*
* 04-bysort.do
*--------------------------------------------------------------*
sysuse nlsw88, clear
* 1) 按是否大学毕业分组 summarize
bysort collgrad: summarize wage tenure
* 2) 等价的 bys 简写
bys collgrad: summarize wage
* 3) 多个分组变量:按 (是否大学毕业 × 是否在南部)
bysort collgrad south: summarize wage
* 4) 先排序再分组(Stata 会自动 sort,但显式写更安全)
sort collgrad
by collgrad: summarize wage
* 5) 计算组内均值并保留
bysort collgrad: egen wage_mean_coll = mean(wage)
* 6) 分组 + tabulate:列联表
tab collgrad south, row col
05 相关系数矩阵:pwcorr 带星号
Table 1 之后经常跟一张 Table 2:相关系数矩阵。它让审稿人快速看到"哪些变量彼此高度相关",从而预判多重共线性问题。最常用的命令是 pwcorr——pw 指 pairwise deletion,即每一对变量只用这两个都不缺失的观测计算相关系数,而不是 listwise 删除。sig 选项报告 p 值,star(.05) 在显著的相关系数上打星号。
*--------------------------------------------------------------*
* 05-pwcorr.do
*--------------------------------------------------------------*
sysuse nlsw88, clear
* 1) 基础相关系数矩阵
pwcorr wage tenure ttl_exp age collgrad
* 2) 带 p 值
pwcorr wage tenure ttl_exp age collgrad, sig
* 3) 带星号(最常用!)
* star(.05) 表示 |r| 显著在 5% 水平时打 *
pwcorr wage tenure ttl_exp age collgrad, sig star(.05)
* 4) 注意:corr 命令是 listwise deletion
* 与 pwcorr 结果可能略不同,论文里统一用 pwcorr
两个解释变量相关系数超过 0.8 才需要警惕。常见的"size 与 lev"、"age 与 tenure"通常相关 0.3–0.5,不构成问题。真正要看 VIF(方差膨胀因子)时,跑 estat vif。
06 estpost + esttab:导出三线表
这是本页最重要的一组命令。estpost 把 summarize、tabstat 等命令的输出"打包"成一个 est 估计量对象,再由 esttab 把它渲染成三线表。这套流程可以直接产出符合期刊格式的 Word/Excel/LaTeX 表格。
*--------------------------------------------------------------*
* 06-estpost-esttab.do —— 一键导出三线表
*--------------------------------------------------------------*
ssc install estout, replace // 首次运行时安装
sysuse nlsw88, clear
* 先把变量标签打好(关键!)
label variable wage "Hourly wage (USD)"
label variable tenure "Tenure (years)"
label variable ttl_exp "Total experience (years)"
label variable age "Age"
label variable collgrad "College graduate (1=Yes)"
* ---------- 1) estpost 打包描述性统计 ----------
estpost tabstat wage tenure ttl_exp age collgrad, ///
statistics(n mean sd p50 min max) columns(statistics)
* ---------- 2) esttab 渲染成三线表 ----------
* cells() 控制列布局:mean(fmt(3)) sd(fmt(3)) ...
esttab . using "output/Table1_descriptive.rtf", replace ///
cells("count(fmt(0)) mean(fmt(3)) sd(fmt(3)) p50(fmt(3)) min(fmt(3)) max(fmt(3))") ///
noobs nonumber nomtitle label ///
title("Table 1. Descriptive Statistics") ///
collabels("N" "Mean" "Std Dev" "Median" "Min" "Max")
* ---------- 3) 相关系数矩阵也走 estout 流程 ----------
estpost correlate wage tenure ttl_exp age, matrix listwise
esttab . using "output/Table2_corr.rtf", replace ///
unstack not noobs nonumber label ///
title("Table 2. Correlation Matrix")
07 导出到 Word / Excel(putexcel / outreg2)
除了 esttab,Stata 里还有两条主流导出路径:
- esttab / outreg2 → .rtf:rtf 文件用 Word 打开后就是三线表,直接复制进论文。这是中文顶刊最常用的路径。
- putexcel → .xlsx:Stata 15+ 自带的 Excel 导出命令,适合需要精细排版(合并单元格、颜色、字体)时使用。
*--------------------------------------------------------------*
* 07-export.do
*--------------------------------------------------------------*
sysuse nlsw88, clear
* ---------- 路径 A:outreg2 导出回归表 ----------
ssc install outreg2, replace
reg wage tenure ttl_exp collgrad
outreg2 using "output/reg_baseline.doc", ///
tstat alpha(0.01 0.05 0.1) symbol(***, **, *) ///
keep(tenure ttl_exp collgrad) ///
title("Table 3. Baseline Regression") replace
* ---------- 路径 B:putexcel 精细控制 ----------
* 1) 先把统计量存成标量
quietly summarize wage
scalar n = r(N)
scalar mean = r(mean)
scalar sd = r(sd)
* 2) putexcel 写到 .xlsx
putexcel set "output/desc_summary.xlsx", replace
putexcel A1 = ("Variable") B1 = ("N") C1 = ("Mean") D1 = ("SD")
putexcel A2 = ("wage") B2 = (n) C2 = (mean) D2 = (sd)
* 打开 Excel 即可看到 Table
08 数据分布可视化:histogram / kdensity
Table 1 报告数字,图告诉你"分布形状"。对核心变量做一张直方图(histogram)加核密度(kdensity)叠加图,是审稿人最爱看的"你对数据熟不熟"的证据。
*--------------------------------------------------------------*
* 08-visualize.do
*--------------------------------------------------------------*
sysuse nlsw88, clear
* 1) 直方图(默认频率)
histogram wage, ///
title("Hourly Wage Distribution") ///
xtitle("Hourly wage (USD)") ///
ytitle("Frequency")
graph export "output/hist_wage.png", replace width(1600)
* 2) 直方图 + 正态密度叠加(freq 改为 density)
histogram wage, frequency normal ///
title("Wage Histogram with Normal Overlay")
* 3) 核密度估计(kdensity)
kdensity wage, ///
title("Kernel Density of Wage") ///
xtitle("Hourly wage (USD)")
graph export "output/kdensity_wage.png", replace width(1600)
* 4) 分组叠加:处理组 vs 控制组的密度对比
* 这在 DID / RDD 论文里几乎是标配
kdensity wage if collgrad==0, lcolor(navy) ///
|| kdensity wage if collgrad==1, lcolor(maroon) ///
legend(label(1 "Non-college") label(2 "College")) ///
title("Wage Density: College vs. Non-college")
graph export "output/kdensity_bygroup.png", replace width(1600)
09 论文案例:Table 1 的范式
10 常见错误与调试
很多同学写完 estpost tabstat ... 直接 esttab . using ...,结果导出的表只有一个 mean 列。正确做法:在 esttab 里写 cells("count(fmt(0)) mean(fmt(3)) sd(fmt(3))") 显式指定列。
corr 用 listwise deletion,pwcorr 用 pairwise deletion。当有缺失值时两者数值会不同。论文里请统一用 pwcorr,并在脚注里写明"pairwise correlations"。
用 esttab 导出 .rtf 时,如果变量标签是中文,Word 打开可能乱码。两个解决:(1) 用 esttab, ... , booktabs 导出 LaTeX;(2) 在 do 文件开头加 set locale_utf8 on,或直接用 esttab using "...", replace encoding(UTF-8)。
直接写 by collgrad: summarize wage 在新版 Stata 里能跑(Stata 自动 sort),但老版本会报 "not sorted"。规范写法:sort collgrad 后再 by collgrad:,或直接用 bysort collgrad:。
11 进阶学习资料
- estout 官方手册:Ben Jann 写的 "Making regression tables from stored estimates"(Stata Journal),是 esttab 系列的"圣经"。
- Stata 官方:
help estpost、help esttab、help pwcorr、help putexcel。 - 教材:Cameron & Trivedi, Microeconometrics Using Stata 第 13 章"Production of tables and graphs"。
- 中文资源:陈强《高级计量经济学及 Stata 应用》第 2 章;知乎/经管之家"estout 导出三线表"专题帖。
- 图表示范:浏览 AER 官网的最新论文,挑一篇你感兴趣的,把它 Table 1 的结构抄下来,作为你自己论文的模板。