本文へ移動
cccskills
無料GitHub で公開

data-pipeline

End-to-end data pipeline for empirical research: fetch economic data from APIs (FRED, World Bank, IMF, BLS, OECD, Yahoo Finance), clean and transform raw data, construct strategy-specific variables, and validate panel structure. Use when asked to fetch data, download data, clean data, merge datasets, prepare analysis-ready data.

インストール方法を見る

含まれるファイル(1)

  • SKILL.md16.1 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Data-Pipeline

Purpose

本 skill 是一体化数据管道,由 /data 命令调用,负责完整的数据工作流:

  1. 数据获取(Part 1)— 从多个 API 自动下载原始数据
  2. 数据清洗与转换(Part 2)— 合并、去重、缺失值处理、异常值检测、变量构建
  3. 质量保证(Part 3)— 验证面板结构、进行质量审计、输出分析就绪的数据集

产出:data/clean/[project_name]_clean.[dta|parquet|csv] + data/clean/cleaning_log.md


When to Use

  • 由 /data 命令自动调用(主要场景,分别在 Step 1 和 Step 2 调用)
  • 独立触发:用户需要获取 + 清洗数据的完整流程

Part 1: Data Acquisition(数据获取)

Step 0: API Key Setup Check

执行任何代码前必须先检查所需 API Key。

  1. 读取 [plugin_root]/.env 文件(与 CLAUDE.md 同目录,即插件根目录)
  2. 检查 FRED_API_KEY 和 BLS_API_KEY

若 FRED_API_KEY 缺失或为空:

若 BLS_API_KEY 缺失:

若 .env 已存在且 Key 已设置:

  • 静默加载,通过 python-dotenv 注入所有代码中
from dotenv import load_dotenv
load_dotenv()  # 自动从 CWD 及父目录搜索 .env

⚠️ .env 格式要求: 标准 KEY=VALUE 格式(每行一个),非 JSON。若为 JSON 格式,需先转换。


Step 1: 接收调用上下文

本 skill 由 /data 传入结构化上下文,无需重新询问用户。

接收参数:

参数说明示例
target_datasets目标数据集名称列表["FRED宏观", "World Bank"]
variables变量清单Y=gdp_growth, Z=tariff_rate
time_range起止年份与频率2000–2023, 年度
geo_scope地理范围中国31省 / 美国全国
identification_strategy识别策略DiD / RDD / IV / Panel FE
output_format输出格式csv(默认)/ dta / parquet

Step 2: 选择合适的数据源

根据传入的数据集名称和地理范围,选择对应 API:

数据类型最佳数据源方式
美国宏观时间序列FREDfredapi
全球发展指标World Bankwbdata
美国劳动力市场BLS API v2requests(需分块)
跨国宏观/金融IMF WEOimf-reader
金融资产价格Yahoo Financeyfinance

无法自动获取的数据源(需用户手动下载):

  • OECD:数据端点受 Cloudflare 防护,沙箱不可访问。优先用 IMF WEO 替代。
  • 国家统计局(NBS):API 限制中国大陆 IP。请前往 https://data.stats.gov.cn 下载后走手动上传流程。

Step 3: 生成并执行获取代码

生成的脚本必须包含:

① 基础要素

  • API Key 通过环境变量注入(python-dotenv),不硬编码
  • API 请求失败的错误处理(捕获异常、打印错误信息)
  • 系列 ID 的中英文注释说明

② 输出路径规范

from datetime import date
filename = f"data/raw/{source_name}_{date.today().strftime('%Y%m%d')}.csv"
df.to_csv(filename, index=False)

③ 写入 data/raw/data_log.md

log_entry = f"""
## {dataset_name} 获取记录
- 获取日期:{date.today()}
- 数据来源:{source_name}
- 原始文件路径:{filename}
- 变量数:{df.shape[1]},观测数:{df.shape[0]}
- 频率:{frequency}
- 合并键:{merge_key}
"""
os.makedirs("data/raw", exist_ok=True)
with open("data/raw/data_log.md", "a", encoding="utf-8") as f:
    f.write(log_entry)

④ 关键变量验证

required_vars = [Y_var, D_var, Z_var] + control_vars
available = df.columns.tolist()
found    = [v for v in required_vars if v in available]
missing  = [v for v in required_vars if v not in available]

print("=== 变量到位检查 ===")
for v in found:
    print(f"✅ {v}")
for v in missing:
    print(f"⚠️  {v} — 需在清洗阶段处理")

Part 2: Data Cleaning & Transformation(数据清洗与转换)

Step 0: 接收调用上下文

接收参数(来自 identification-memo.md):

参数说明示例
identification_strategy识别策略DiD / RDD / IV
Y_var结果变量log_gdp_growth
D_var处理变量policy_dummy
Z_var识别变量tariff_rate_1990
control_vars协变量列表["log_gdp", "population"]
id_var面板个体标识province_code
time_var时间变量year
input_files原始数据文件路径["data/raw/fred_*.csv"]
merge_plan多源合并方案主文件 + 辅助文件

Step 1: 多源数据合并(条件触发)

触发条件: input_files 包含 ≥2 个文件且 merge_plan 已确认

1.1 执行合并

import pandas as pd

df = pd.read_csv("data/raw/[主文件]")
n_before = len(df)

for aux_file, merge_key, how in merge_plan:
    aux = pd.read_csv(f"data/raw/{aux_file}")
    df = df.merge(aux, on=merge_key, how=how, suffixes=("", "_aux"))
    print(f"合并 {aux_file}:{len(df):,} 行({how} join on {merge_key})")

1.2 合并质量报告

n_after = len(df)
match_rate = n_after / n_before * 100
print(f"匹配率:{match_rate:.1f}%")

dups = df.duplicated(subset=merge_key).sum()
if dups > 0:
    print(f"⚠️  发现 {dups} 行重复")

for v in [Y_var, D_var, Z_var]:
    miss_rate = df[v].isna().mean() * 100
    print(f"{v} 缺失率:{miss_rate:.1f}%")

若匹配率低于 70%,需向用户报告并说明原因。


Step 2: 通用清洗流水线

按以下顺序执行,每步都在 cleaning_log.md 中记录样本量和关键指标变化。

2.1 重复观测检测与处理

dup_mask = df.duplicated(subset=[id_var, time_var], keep=False)
n_dups = dup_mask.sum()
print(f"重复观测:{n_dups} 行")

if n_dups > 0:
    df_dups = df[dup_mask]
    df_dups.to_csv("data/clean/duplicates_removed.csv", index=False)
    df = df.drop_duplicates(subset=[id_var, time_var], keep="first")

2.2 缺失值编码识别与处理

MISSING_CODES = [-99, -88, -77, -9, 9999, 99999, -9999]
df.replace(MISSING_CODES, pd.NA, inplace=True)

miss_report = df.isnull().mean().sort_values(ascending=False)
miss_high = miss_report[miss_report > 0.05]

print("缺失率 > 5% 的变量:")
for var, rate in miss_high.items():
    print(f"  {var}: {rate:.1%}")

缺失值处理决策:

情形推荐处理
Y / D 缺失明确报告,删除;不得插补
Z 缺失明确报告;可能非随机
协变量 < 5%可考虑均值/中位数插补
协变量 5–20%建议多重插补或敏感性分析
协变量 > 20%寻找替代变量

2.3 变量类型修正与命名规范化

# 列名统一为 snake_case
df.columns = (
    df.columns
    .str.strip()
    .str.lower()
    .str.replace(r"\s+", "_", regex=True)
    .str.replace(r"[^a-z0-9_]", "", regex=True)
)

# 关键变量类型修正
df[time_var] = pd.to_numeric(df[time_var], errors="coerce").astype("Int64")
df[id_var]   = df[id_var].astype(str).str.strip()

for col in numeric_vars:
    df[col] = pd.to_numeric(df[col], errors="coerce")

2.4 异常值检测与处理

def winsorize(series, lo=0.01, hi=0.99):
    """将连续变量在 lo/hi 分位数处缩尾"""
    lo_val = series.quantile(lo)
    hi_val = series.quantile(hi)
    return series.clip(lo_val, hi_val)

# 仅对连续型协变量缩尾,不对 Y / D / Z 自动缩尾
for col in continuous_controls:
    n_outliers = ((df[col] < df[col].quantile(0.01)) |
                  (df[col] > df[col].quantile(0.99))).sum()
    print(f"{col}: {n_outliers} 个观测超出 [p1, p99]")
    df[f"{col}_w"] = winsorize(df[col])  # 保留原始变量

⚠️ 经济学提醒:Winsorize 需要经济学判断,不是默认必须步骤。

2.5 变量标签(Stata 输出时)

label variable `Y_var'     "结果变量:[描述]"
label variable `D_var'     "处理变量:[描述]"
label variable `Z_var'     "识别变量:[描述]"

Step 3: 识别策略专属变量构建

根据传入的 identification_strategy,自动触发对应的变量构建模块。


策略 A: 双重差分(DiD / Event Study)

* DiD 核心变量构建
gen treated = (group_var == "treated_group")
gen post = (year >= policy_year)
gen treated_post = treated * post
gen event_time = year - policy_year

* 交错处理时点
bysort id: egen first_treated_year = min(cond(treated_post == 1, year, .))
gen relative_time = year - first_treated_year

Python 版本:

df["treated"]      = (df["group_var"] == "treated_group").astype(int)
df["post"]         = (df[time_var] >= policy_year).astype(int)
df["treated_post"] = df["treated"] * df["post"]
df["event_time"]   = df[time_var] - policy_year

first_treated = (df[df["treated_post"] == 1]
                 .groupby(id_var)[time_var].min()
                 .rename("first_treated_year"))
df = df.merge(first_treated, on=id_var, how="left")
df["relative_time"] = df[time_var] - df["first_treated_year"]

策略 B: 断点回归(RDD)

gen running_centered = running_var - cutoff_value
gen above_cutoff = (running_var >= cutoff_value)
gen running_above = running_centered * above_cutoff

Python 版本:

df["running_centered"] = df["running_var"] - cutoff_value
df["above_cutoff"]     = (df["running_var"] >= cutoff_value).astype(int)
df["running_above"]    = df["running_centered"] * df["above_cutoff"]

print(f"阈值以上样本:{df['above_cutoff'].sum()}")

策略 C: 工具变量(IV)

# 范式 1:历史值作工具变量
df["Z_historical"] = df["D_var_baseyear"]

# 范式 2:Bartik 工具
df["Z_bartik"] = (df["industry_share_base"] * df["national_growth"]).groupby(id_var).transform("sum")

# 范式 3:政策 × 时间外生变动
df["Z_policy_interact"] = df["policy_var"] * df["exogenous_shock"]

# 初步检查:Z 与 D 的相关性
corr = df[[Z_var, D_var]].corr().iloc[0, 1]
print(f"Z-D 相关系数:{corr:.3f}")
if abs(corr) < 0.1:
    print("⚠️  相关性较弱,一阶段 F 可能 < 10")

策略 D: 面板固定效应(Panel FE)

# 唯一标识符验证
assert not df.duplicated(subset=[id_var, time_var]).any()

# 面板平衡性检查
counts = df.groupby(id_var)[time_var].count()
is_balanced = (counts == counts.max()).all()
print(f"面板平衡性:{'强平衡' if is_balanced else '弱平衡'}")

# Within / Between 方差分解
df["Y_mean_i"]    = df.groupby(id_var)[Y_var].transform("mean")
df["Y_within"]    = df[Y_var] - df["Y_mean_i"]
var_within    = df["Y_within"].var()
var_between   = df["Y_mean_i"].var()
print(f"Within 方差占比:{var_within / (var_within + var_between):.1%}")

策略 E: 合成控制(Synthetic Control)

assert id_var in df.columns and time_var in df.columns

df["is_treated_unit"] = (df[id_var] == treated_unit_id).astype(int)
df["is_donor"]        = (1 - df["is_treated_unit"])
df["pre_treatment"]   = (df[time_var] < treatment_year).astype(int)
df["post_treatment"]  = (df[time_var] >= treatment_year).astype(int)

n_donors = df[df["is_donor"] == 1][id_var].nunique()
T_pre    = df[df["pre_treatment"] == 1][time_var].nunique()
print(f"控制池规模:{n_donors},预处理期:{T_pre}")

if T_pre < 5:
    print("⚠️  预处理期较短,匹配质量可能受限")

Step 4: 面板结构验证(条件触发)

触发条件: identification_strategy 为 DiD、Panel FE 或 Synthetic Control

print("=== 面板结构验证 ===")
print(f"观测总数:{len(df):,}")
print(f"个体数:{df[id_var].nunique()}")
print(f"时间期数:{df[time_var].nunique()}")
print(f"时间范围:{df[time_var].min()} – {df[time_var].max()}")

obs_per_unit = df.groupby(id_var).size()
print(f"每个体观测数:min={obs_per_unit.min()}, max={obs_per_unit.max()}")

if obs_per_unit.min() == obs_per_unit.max():
    print("✅ 强平衡面板")
else:
    print(f"⚠️  不平衡面板")

Part 3: Quality Assurance(质量保证)

Step 1: 关键变量最终审计

print("\n=== 关键变量最终状态 ===")
audit_vars = [Y_var, D_var, Z_var] + control_vars
for v in audit_vars:
    if v not in df.columns:
        print(f"❌ {v}:不存在!")
        continue
    miss = df[v].isna().mean()
    mean = df[v].mean() if df[v].dtype != object else "N/A"
    std  = df[v].std()  if df[v].dtype != object else "N/A"
    print(f"{'✅' if miss < 0.05 else '⚠️ '} {v}: 缺失={miss:.1%}, 均值={mean:.4g}, 标准差={std:.4g}")

Step 2: 保存清洗后数据集

import os
from datetime import date

os.makedirs("data/clean", exist_ok=True)

output_path_parquet = f"data/clean/{project_name}_clean.parquet"
df.to_parquet(output_path_parquet, index=False)
print(f"✅ 已保存:{output_path_parquet}({len(df):,} 行 × {df.shape[1]} 列)")

# 如需 Stata 格式
try:
    import pyreadstat
    output_path_dta = f"data/clean/{project_name}_clean.dta"
    pyreadstat.write_dta(df, output_path_dta)
    print(f"✅ 已保存:{output_path_dta}")
except ImportError:
    print("(如需 .dta 格式,请安装 pyreadstat)")

Step 3: 写入 cleaning_log.md

每次清洗完成后自动追加:

log = f"""
## 数据清洗记录 — {project_name}
- 清洗日期:{date.today()}
- 识别策略:{identification_strategy}
- 输入文件:{input_files}
- 输出文件:data/clean/{project_name}_clean.parquet

### 样本量变化
| 步骤 | 操作 | 样本量 |
|------|------|--------|
| 原始数据(合并后) | — | {n_raw:,} |
| 删除重复观测 | ({id_var}, {time_var}) | {n_after_dedup:,} |
| 删除 Y/D 缺失 | 结果/处理变量 | {n_after_ymiss:,} |
| 最终样本 | — | {len(df):,} |

### 关键变量缺失率(清洗后)
| 变量 | 角色 | 缺失率 |
|------|------|--------|
{chr(10).join(f"| {v} | {role} | {df[v].isna().mean():.1%} |" for v, role in zip([Y_var, D_var, Z_var], ["Y", "D", "Z"]))}

### 识别策略专属变量
{chr(10).join(f"- `{v}`:已构建" for v in strategy_vars_built)}

### 数据质量问题记录
{quality_notes}
"""

os.makedirs("data/clean", exist_ok=True)
with open("data/clean/cleaning_log.md", "a", encoding="utf-8") as f:
    f.write(log)
print("✅ 已写入 data/clean/cleaning_log.md")

Common Pitfalls

❌ 常见错误✅ 正确做法
合并前不检查合并键唯一性assert df[key].is_unique
对 Y / D 自动 Winsorize缩尾前须有经济学判断
用全局均值填充 Y / D 缺失Y/D 应删除,不应插补
DiD 用全局政策年份,忽视交错处理用个体自身 first_treated_year
覆盖原始数据data/raw/ 仅读,data/clean/ 用于保存
未记录样本量变化每步都在 cleaning_log.md 记录
合并后不检查匹配率低于 70% 需向用户报告
对 RDD 忘记密度检验McCrary 检验在 EDA 阶段执行

Requirements

pip install pandas pyreadstat python-dotenv fredapi wbdata requests yfinance imf-reader

Related Skills & Commands

  • /data:调用本 skill 的上级命令
  • results-analysis:接收本 skill 的输出,生成描述性统计与探索性分析
  • did-analysis / rdd-analysis / iv-estimation / panel-data:应用本 skill 构建的变量

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Create Beamer-style academic PPTX presentations using python-pptx. Produces publication-quality .pptx files with navy-blue Metropolis theme (16:9, frame title bars, progress bar) for conference talks, job market presentations, and seminar slides. Called by /present command.

日本語の概要は準備中です。原文の説明を表示しています。

zhouziyue233/great-econometrics82026年4月17日 更新

Econometrics skill for Difference-in-Differences (DID) analysis. Activates when the user asks about: "difference in differences", "DID", "DiD", "diff-in-diff", "parallel trends", "treatment group", "control group", "pre-treatment", "post-treatment", "policy evaluation", "natural experiment", "staggered DID", "event study regression", "two-way fixed effects DID", "callaway santanna", "sun and abraham", "双重差分", "倍差法", "平行趋势", "处理组", "对照组", "政策评估", "事件研究", "交错DID", "渐进处理"

日本語の概要は準備中です。原文の説明を表示しています。

zhouziyue233/great-econometrics82026年4月17日 更新

figure

無料

Called by /plot to generate and upgrade econometric figures to top-journal standards.

日本語の概要は準備中です。原文の説明を表示しています。

zhouziyue233/great-econometrics82026年4月17日 更新

Econometrics skill for instrumental variables and treatment effect estimation. Activates when the user asks about: "instrumental variables", "IV estimation", "2SLS", "two-stage least squares", "endogeneity", "weak instruments", "first stage", "Sargan test", "overidentification", "propensity score matching", "PSM", "average treatment effect", "ATT", "LATE", "local average treatment effect", "endogenous regressor", "instrument validity", "工具变量", "两阶段最小二乘", "内生性", "弱工具变量", "倾向得分匹配", "平均处理效应", "处理效应", "局部平均处理效应"

日本語の概要は準備中です。原文の説明を表示しています。

zhouziyue233/great-econometrics82026年4月17日 更新

Search, summarize, and synthesize economics literature. find research gaps, position your contribution.

日本語の概要は準備中です。原文の説明を表示しています。

zhouziyue233/great-econometrics82026年4月17日 更新

ml-causal

無料

Econometrics skill for machine learning methods in causal inference. Activates when the user asks about: "causal forest", "generalized random forest", "GRF", "double machine learning", "DML", "debiased machine learning", "LASSO for variable selection", "post-LASSO", "heterogeneous treatment effects", "CATE", "conditional average treatment effect", "BLP analysis", "CLAN analysis", "causal tree", "honest estimation", "因果森林", "双重机器学习", "异质性处理效应", "条件平均处理效应", "LASSO变量选择", "机器学习因果推断", "去偏机器学习"

日本語の概要は準備中です。原文の説明を表示しています。

zhouziyue233/great-econometrics82026年4月17日 更新

zhouziyue233 のスキルをすべて見る

このスキルの問題を報告する