前置条件与学习依赖 / PREREQUISITES
① 统计 / 计量基础
OLS 与固定效应、描述性统计、面板数据结构;能读懂 reg / reghdfe 输出。
② 软件 / 计算前置
Stata 17+(或 R / Python 任选其一),会用 cddologmkdir;能在终端 / Stata 命令窗口里跑脚本。
③ 站内前置页面
先过 01 数据清洗02 数据合并04 基准回归,再进入复现实操。
④ 难度分级
工程 · 入门到进阶

01 为什么要学复现:复现包是实证研究的"标准答案"

读论文时,我们读到的是一篇被高度压缩的故事:一张主回归表、几张稳健性图、一段文字解释识别策略。但论文从原始数据到那张表之间,藏着几百个决策——哪些观测被删、缺失值怎么填、异常值怎么处理、行业代码如何统一、政策冲击变量怎么构造、固定效应按什么层级加、标准误聚在哪一层。这些决策在正文里通常只占半句话,甚至完全不提。审稿人看不到,读者更看不到。复现包(replication package)就是把这几百个决策全部摊开、写成可重跑的代码和数据。

把复现包当作"标准答案"来学,有三个立刻能拿到的好处。第一,它告诉你一篇顶刊论文在工程上到底长什么样——不是 abstract 里那个抽象的识别故事,而是 main.do 里第 37 行那个 drop if missing(industry)。第二,它是你自己写代码的"范文":变量命名、文件夹组织、注释风格、log 文件管理、表输出格式,都能直接照抄。第三,复现是训练"识别思维"最快的方式——你必须搞懂每一步为什么这么做,才能改得动它;而改不动,就说明你还没读懂。

反过来说,一个不会复现论文的研究者,写出来的实证几乎一定是脆弱的。因为他没见过"一篇被严格审稿、被公开复现的论文"在工程上有多讲究:从 set seedesttab,从 cdsave, replace,每一行都有讲究。本站前面几页讲的是"方法是什么",这一页讲的是"顶刊的方法是怎么被代码组织起来的"。

✓ 复现 vs 自己做研究的关系

复现不是"抄别人结果"。复现的目标有三:(1) 跑通——主表主图能复出来,数字对得上;(2) 读懂——每一步代码为什么这么写、删了谁、留了谁;(3) 改动——在别人的复现包上改一个变量、加一个稳健性、换一个样本,变成自己的小练习。第三点才是复现的真正价值。

02 复现包结构解读

一个规范的复现包,无论作者用 Stata、R 还是 Python,骨架都高度同构。你拿到一个 zip 解压后,应该立刻认出下面这些东西。如果缺了其中任何一个,这个复现包的质量就要打问号。

2.1 顶层结构:README + 主程序 + data/ + output/

打开复现包根目录,第一层通常是:

  • README.md / README.txt:入口说明书。写清楚作者、论文标题、期刊、运行环境(Stata 版本 / R 版本 / Python 版本)、外部命令清单、运行顺序、预期运行时间、常见报错。这是你读复现包第一个要打开的文件。
  • 主程序(main.do / run_all.do / master.R / run_all.py):一键从原始数据跑到最终表的脚本。它通常会 cd 到根目录、依次调用各个 do 文件、最后输出表和图。
  • code/ 或 do/ 文件夹:拆分好的子程序,通常按"数据清洗 → 描述统计 → 主回归 → 稳健性 → 图表输出"分文件。
  • data/raw/ 或 raw_data/未经任何处理的原始数据。这是你的起点——复现必须从 raw 重新跑到最终表,而不是直接用作者已经洗好的中间数据。
  • data/derived/ 或 data/intermediate/:清洗过程中产生的中间数据(合并好的面板、生成的变量、缩尾后的数据)。
  • data/analysis/:最终回归用的分析样本。这张表的行数应该和主回归表的 N 对得上。
  • output/tables/ 与 output/figures/:最终的 .csv / .xls / .tex 表格和 .png / .pdf 图。
  • log/:每次运行留下的日志文件,用来核对输出。

2.2 三层数据:raw → derived → analysis

这是复现包里最重要的分层思想。raw 是只读的,你不允许修改它;derived 是中间过程,可重新生成;analysis 是最终跑回归用的表。一个复现包如果把这三层混在一起——比如直接在 raw 数据上 replacedropsave, replace——那它几乎一定跑不通,因为你没法重跑,也不知道作者到底删了谁。

对应到论文里:raw 数据是"原始观测",derived 是"清洗后的中间样本",analysis 是"最终回归样本"。三者之间每一步删了多少观测,都应该能在代码里数清楚——这就是下一页要讲的"样本构造 flow chart"。

层级目录可否修改对应论文中的概念
rawdata/raw/只读,绝不修改原始观测(如 CSMAR 下载的原始 dta)
deriveddata/derived/可由代码重新生成清洗、合并、缩尾后的中间样本
analysisdata/analysis/可由代码重新生成最终回归样本(N 与主表一致)

03 如何识别主程序:从 README 到调用链

拿到一个复现包,作者常常给你 20 个 do 文件,你不知道该先跑哪个。识别主程序有三种办法,按可靠性排序:

  1. 看 README。规范的 README 会直接写"在 Stata 里运行 do main.do"。如果 README 没写,看下一条。
  2. 找名字里带 main / master / run_all / 00_master / setup 的文件。这类文件通常一开头就 clear allcd 到根目录、set more offlog using,然后一串 do "code/01_clean.do"do "code/02_merge.do"
  3. 用 grep 搜调用关系。在 Stata 里或用终端 grep -rn 'do "' code/,找出哪个文件被最多文件调用、且它自己不调用别人——它就是叶子节点(最终输出表);反过来,谁调用了最多文件、自己不被别人调用,谁就是主程序。

找到主程序后,你要在脑子里画出一张调用链图

text · 调用链示意
main.do
 ├─ 00_setup.do        ← cd, set seed, 安装外部命令, 全局宏
 ├─ 01_clean_raw.do    ← 读 data/raw/*.dta → 清洗 → 存 data/derived/clean.dta
 ├─ 02_merge.do        ← 合并多个 derived → 面板 → data/derived/panel.dta
 ├─ 03_sample.do       ← 筛选最终样本 → data/analysis/final.dta
 ├─ 04_desc.do         ← 描述性统计表 → output/tables/t1_desc.tex
 ├─ 05_main_reg.do     ← 主回归 → output/tables/t2_main.tex
 ├─ 06_robust.do       ← 稳健性 → output/tables/t3_robust.tex
 └─ 07_figures.do      ← 图 → output/figures/fig1.pdf

这张图一旦画出来,你就知道:data/raw 是源头,output/tables 是终点,中间每个 do 文件都是一条加工线。复现失败时,沿着这条线倒查——是哪个 do 文件产生的中间数据出了问题。

⚠ 小心"隐藏主程序"

有些论文的复现包把主程序藏在 Replication.dorun.domake.do 这种不起眼的名字里,甚至藏在二级文件夹。如果 README 没写、根目录看不出入口,就用上面第 3 条 grep 方法找。

04 复现五步走

第一步:环境配置(不要跳过)
按 README 装齐外部命令:ssc install reghdfe, replacessc install estout, replacessc install ftools, replace 等。把 cd 改成你自己机器上复现包的路径。永远不要直接改作者的 do 文件里的硬路径——在主程序最开头加一个全局宏,所有路径都引用它。
第二步:数据下载与解压
raw 数据通常很大(几百 MB 到几 GB),作者可能放在 Zenodo / Harvard Dataverse / 自己主页。下载后严格放进 data/raw/,保持作者命名。不要自己重命名——主程序里读的就是这个名字。
第三步:运行主程序,从 raw 一路跑到 output
在 Stata 里 do main.do。第一次跑几乎一定报错:路径错、外部命令没装、Stata 版本不兼容、某个变量名拼错。逐个修,不要跳着跑——必须从 raw 重新生成所有中间数据,否则你跑的不是"复现",是"作者已经洗好的半成品"。
第四步:核对输出(这一步比跑通更重要)
把你 output/tables/ 里生成的表,和论文正文里的表逐列比对:系数大小、星号、N、R²。不需要每个数字都一模一样(版本差异、浮点误差会导致第三位小数不同),但主系数的符号、量级、显著性必须一致。对不上的列,回去查那一步 do 文件。
第五步:修改与扩展(从复现走向自己的研究)
挑一个"无害"的改动练手:换一个缩尾比例、加一个控制变量、把标准误从聚类到 firm 改成 clustering to industry、换一个子样本。改完重新跑 main.do,看主系数稳不稳。这一步是把"读代码"变成"写代码"的关键一跃。

05 案例:Lane (2025, QJE) "Manufacturing Revolutions"

QJE · 2025
Manufacturing Revolutions: Industrial Policy and Industrialization in South Korea
Nathan Lane, The Quarterly Journal of Economics, 140(3), 2025, pp. 1683–1741. DOI: 10.1093/qje/qjaf025
该文利用韩国 1973–1979 年"重化工业(HCI)"产业政策的引入与终止,识别产业政策对工业化的因果效应。作者利用新组装的微观数据,发现 HCI 政策直接推动了被 targeted 行业的扩张与动态比较优势;通过投入产出网络,政策间接惠及下游中间品用户;政策结束后效果仍然持续。

Lane (2025) 是近年产业政策实证的代表作。这类基于新组装历史微观数据的 QJE 论文,其复现包通常遵循下面的一般模式(具体文件结构以作者在 QJE 补充材料 / 个人主页公开的 replication package 为准):

  • raw 数据层:韩国经济统计年鉴、行业普查(industry census)、企业层面报表、投入产出表(input-output tables)、政策文件档案。这些是作者一手收集、数字化整理的历史数据,是论文最核心的"硬资产"。
  • derived 数据层:把不同来源的行业代码统一到同一口径(韩国 SIC → 国际 ISIC),构造行业层面的产出、就业、资本、增加值面板;用投入产出矩阵构造下游/上游 exposure 变量。
  • analysis 数据层:以行业 × 年为单位的最终面板,处理变量 = 该行业是否被 HCI targeted(或 exposure 强度),结果变量 = 产出增长、TFP、比较优势指数。
  • 识别策略:利用政策在行业间的 cross-sectional 差异 + 时间上的引入/退出事件,类似事件研究(event-study)+ 双重差分思路;并通过 IO 网络把处理效应从直接 targeted 行业传导到下游用户行业。
  • 输出层:主回归表(直接效应)、下游溢出表、动态效应图(event-study coefficients over time)、政策结束后的持续性图。
ℹ 如何找 Lane 2025 的复现包

QJE 要求作者公开 replication package,通常放在 OUP 网站的论文补充材料(Supplementary material)区,或作者本人主页(Nathan Lane 在 Erasmus / Warwick 等机构的 faculty page)。下载后按本页第二节的结构对照阅读:先看 README,再找 main.do,再追踪 raw → derived → analysis 三层。如果你在复现中发现某一步和本页描述的一般模式不同,以实际代码为准——本页给的是"这类论文通常长什么样"的地图,不是该论文的精确目录。

06 常见错误与踩坑清单

错误 1:路径硬编码(Hard-coded paths)

作者在自己电脑上写的 cd "C:/Users/Nathan/Dropbox/HCI/replication",你拿到后直接跑,必然报错。正确做法:在 main.do 最开头定义一个全局宏:

stata · 路径宏示例
* 在 main.do 开头,只改这一行
global root "C:/你的路径/Lane2025_replication"
cd "$root"

* 之后所有 do 文件都用 "$root/data/raw/..." 引用路径
* 不要在每个 do 文件里写死自己的电脑路径

错误 2:相对路径错误

主程序里写 do "code/01_clean.do",这个相对路径是相对于当前工作目录的。如果你手动 do code/01_clean.do 而不是从 main.do 调用,工作目录可能不在根目录,就会找不到文件。永远只从 main.do 跑,不要单独调子程序。

错误 3:随机种子未固定

复现包里如果有 bootstrap、随机分组、随机抽样,却没有 set seed,那你每次跑结果都会不一样——这不是复现错了,是代码本身不可复现。正确做法:主程序第一行就写 set seed 20250801(或作者指定的种子)。如果你自己做扩展,也必须固定种子,否则审稿人无法核对。

错误 4:外部命令版本依赖

作者用的是 Stata 17 + reghdfe v6.x,你装的是最新版 v7.x,语法可能不兼容(例如 absorb() 参数变化)。解决:先按 README 指定版本装;如果 README 没写,跑通后遇到报错,去 ssc describe reghdfe 看版本,必要时降级。自己写新代码时,在 log 开头用 which reghdfe 记录版本号。

错误 5:直接改 raw 数据

新手最常犯:打开 data/raw/industry.dta,发现一个变量名不对,直接 rename 然后 save, replace。从此你再也跑不出作者的结果,因为 raw 被污染了。铁律:raw 只读,所有清洗都在 derived 层做。

错误 6:跳过中间步骤直接跑最终回归

看到 05_main_reg.do 里有一行 use "data/analysis/final.dta",作者已经把 final.dta 放在包里了,你直接跑这一个文件,"结果对得上"——恭喜你,你什么都没复现。真正的复现必须从 raw 重新生成 final.dta,否则你只是在验证作者存好的那张表,而不是他的代码。

⛔ 复现的底线

复现不是"跑通就算赢"。如果你跑出来的主系数和论文差了一倍、符号反了、星号没了,不要假装没看见。回到调用链,一步一步比对中间样本的 N、均值、关键变量分布——差异一定藏在某一步 drop if 里。

07 完整示例:一个最小复现包的目录树 + 主程序

下面用一个模拟的"某产业政策对企业产出影响"的复现包,演示规范的目录组织和主程序写法。你可以照这个骨架搭自己的项目。

目录树

text · replication_template/
replication_template/
├── README.md                  # 说明:作者、期刊、运行环境、运行顺序
├── main.do                    # 主程序(一键从 raw 跑到 output)
├── code/
│   ├── 00_setup.do            # 全局设置
│   ├── 01_clean.do            # 清洗 raw → derived
│   ├── 02_merge.do            # 合并 → derived/panel.dta
│   ├── 03_sample.do           # 构造分析样本 → analysis/final.dta
│   ├── 04_descriptive.do      # 描述性统计 → output/tables/t1.tex
│   └── 05_main_reg.do         # 主回归 → output/tables/t2.tex
├── data/
│   ├── raw/                   # 只读,原始下载数据
│   │   ├── firm_raw.dta
│   │   └── policy_raw.dta
│   ├── derived/               # 中间数据(可重生成)
│   └── analysis/              # 最终回归样本
├── output/
│   ├── tables/
│   └── figures/
└── log/                       # 每次运行的日志

main.do(带完整中文注释)

stata · main.do
*==============================================================
* 主程序:从 raw 数据一键复现全部表格
* 用法:改下面 global root 为你本机路径,然后 do main.do
*==============================================================
clear all
set more off
set varabbrev off
set seed 20260911                // 固定随机种子,保证可复现

* --- 1. 路径设置(只改这一行)---
global root "C:/Users/你/Projects/replication_template"
cd "$root"

* --- 2. 新建输出文件夹(如不存在)---
capture mkdir "output/tables"
capture mkdir "output/figures"
capture mkdir "log"

* --- 3. 启动日志 ---
capture log close
log using "log/run_$S_DATE.log", replace

* --- 4. 安装并检查外部命令 ---
* (首次运行取消下面注释)
* ssc install reghdfe, replace
* ssc install estout, replace
which reghdfe
which estout

* --- 5. 按调用链依次执行 ---
do "code/00_setup.do"
do "code/01_clean.do"        // raw -> derived/clean_firm.dta
do "code/02_merge.do"        // + policy -> derived/panel.dta
do "code/03_sample.do"       // -> analysis/final.dta
do "code/04_descriptive.do"  // -> output/tables/t1_desc.tex
do "code/05_main_reg.do"     // -> output/tables/t2_main.tex

* --- 6. 完成 ---
display _n "===== 全部跑完,请检查 output/tables/ ====="
log close

03_sample.do(样本构造,演示如何记录 N 变化)

stata · code/03_sample.do
*==============================================================
* 03_sample.do:从 derived/panel.dta 构造最终分析样本
* 每一步都用 count 记录 N,方便做 flow chart
*==============================================================
use "$root/data/derived/panel.dta", clear

* 初始 N
count
scalar N0 = r(N)
display "初始观测: " N0

* 步骤1:只保留制造业
keep if industry_sector == "manufacturing"
count
scalar N1 = r(N)
display "保留制造业后: " N1 " (删了 " N0-N1 ")"

* 步骤2:删除关键变量缺失
drop if missing(output, capital, labor, treat)
count
scalar N2 = r(N)
display "删除关键变量缺失后: " N2 " (删了 " N1-N2 ")"

* 步骤3:缩尾 1%/99%(在组内)
winsor2 output capital labor, cuts(1 99) replace by(year)

* 保存最终分析样本
save "$root/data/analysis/final.dta", replace

* 打印 flow chart
display _n "===== 样本构造 flow chart ====="
display "N0 原始面板:    " N0
display "N1 制造业:      " N1
display "N2 无缺失:      " N2
✓ 把这个骨架抄成你自己的项目

下次开始一个新实证项目,先复制这个目录树和 main.do,把里面的模拟数据换成你自己的。从第一天就保持"raw 只读、derived 可重生成、analysis 是终点"的分层,三个月后你会感谢自己——因为你自己的项目也变成了一个别人能复现的复现包。