# 数据清洗与合并 / Data cleaning and merge

所有输入均为本例自产模拟数据，不代表真实企业或研究结果。raw/ 不会被清洗程序修改。firm_id 是五位文本标识，前导零保留；year 是四位年份；revenue 允许合法分组的千位逗号与小数，employees 为非负整数。空数值表示缺失，不补零。实际科研请先重新定义字段与键，不能照搬本例规则。

## 复做 / Rerun

解压到新目录，保留 results/ 参考成果。Python 只需 Python 3 标准库，无软件源或网络请求：

```sh
python clean_merge.py --output-dir rerun/python
```

Stata 在合法安装的独立练习会话中，从包根执行：

```stata
capture mkdir rerun
do clean_merge.do rerun/stata
```

Stata 的 clear all 清空本次会话，replace 覆写指定输出目录的同名成果。先保存已有工作。默认 `do clean_merge.do` 写 results/stata，会覆写参考输出，练习建议使用上面的新目录。Python 也只覆写其指定输出目录。

## 处理规则 / Rules

规范化首尾空格并检查键/数值。先隔离无效输入，再移除规范化后完全相同内容的额外行，保留最早来源行号。对剩余相同键、不同内容的记录，整组标记 key_conflict，保留审计而不选择其中一个值。主表键是 firm_id + year，对照表键是 firm_id。核对唯一性后执行 m:1 合并，保留 matched、master_only 和 lookup_only。

两份审计 CSV 对应原始来源行号，可回查 raw/；清洗不改写原输入。merged-all.csv 包含仅在对照表中的记录，这种记录没有主表年份，不把它当作新增企业年度观测。analysis-ready.csv 保留全部清洗后的主表观测，包括未匹配者。分析时还需按实际模型检查缺失和样本。

Normalize whitespace while preserving text identifiers and raw inputs. Quarantine invalid keys/values; remove only extra exact duplicate content; quarantine all conflicting keys. Validate master firm-year and lookup firm uniqueness, then perform a many-to-one merge. Keep every merge status and preserve missing values. The audit tables link to raw source rows. A lookup-only record is not a new observed firm-year; analysis-ready retains all cleaned master observations, including unmatched ones.

## 本次结果 / Actual reference output

- 主表 16 行：无效 3、额外完全重复 1、冲突 2，保留 10。
- 对照表 10 行：无效 1、额外完全重复 1、冲突 2，保留 6。
- 匹配 8，主表独有 2，对照表独有 1；合并并集 11 行，主表分析准备仍为 10 条。
- 保留 revenue 缺失 1 条、employees 缺失 1 条；不自动删掉这两类缺失。

Actual independent Python and Stata calculations agree on counts, row-level statuses, clean tables and merge values; cross-check.json records this comparison. Files include both programs, the input generator, raw simulated CSV/dictionary, Python/Stata audit and cleaned tables, merged union, analysis-ready table, counts and actual logs. To regenerate the fixture separately: `python generate_inputs.py --output-dir exercise-raw` then `python clean_merge.py --input-dir exercise-raw --output-dir exercise-results`.

官方 merge：https://www.stata.com/manuals/dmerge.pdf
官方 duplicates：https://www.stata.com/manuals/dduplicates.pdf
指南：https://marx-max.aidea-labs.com/blog/2026-10-15-data-cleaning-merge/
案例：https://marx-max.aidea-labs.com/cases/data-cleaning-merge/
本次在 macOS / Python 3.12.14 / Stata 19.5 独立执行，不作为模型自动执行、Windows 真机或真实研究结论的证据。
