来源信息
- 仓库
- brycewang-stanford/Auto-Empirical-Research-Skills
- 最近来源活动
- 2026年7月22日 09:27
- 检测到的 SKILL.md 语言
- 英语
- 星标
- 3,291
- 分支
- 432
安装方式
默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。
检查来源文件
决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。
菜单
默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。
决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/brycewang-stanford/Auto-Empirical-Research-Skills --skill coding-guidelines命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
Route empirical-research requests through the Auto-Empirical Research Skills catalog when this whole repository is installed as one skill in Codex, CodeBuddy, Claude Code, or another IDE. Use to choose and load the right vendored AERS skill for causal inference, econometrics, replication, data acquisition, manuscript writing, peer review and referee responses, citation checking, de-AIGC editing, or full empirical-paper workflows without reading the entire repository at once.
中英双语学术降 AIGC / bilingual academic de-AIGC skill. Removes AI-generated writing signatures from empirical papers in economics, management, and the social sciences — in both English and Chinese. Covers Turnitin AI, GPTZero, Originality.ai on the English side and 知网 AMLC, 万方, 维普 on the Chinese side. Uses a six-step loop (intake → audit → claim-evidence check → differentiated rewrite → five-dimension self-score → cold-reader recheck) with two pattern libraries (22 English + 17 Chinese patterns), section-by-section strategies for empirical papers, and hard protections that keep every number, coefficient, and citation intact.
Use when a research task needs reproducible Kaggle discovery, metadata inspection, bounded public-data downloads, competition or kernel discovery, model discovery, or an explicitly approved Kaggle write/delete operation through the official CLI.
基于 SOC 职业分类
正在显示 SKILL.md
| name | coding-guidelines |
| description | Standardized Python & Stata coding practices for empirical research projects |
Version: 1.0 Last Updated: January 2026 Purpose: Standardized coding practices for empirical research projects
ProjectName/
├── Code/ # All analysis scripts
│ ├── [Number]_[Name].py # Data processing (Python)
│ ├── AN_[Number]_[Name].do # Analysis scripts (Stata)
│ ├── AN_[Number]_[Name].py # Analysis scripts (Python)
│ ├── LogFiles/ # Stata log files
│ └── README.md # Project documentation
├── Data/
│ ├── Raw/ # Original data (never modify)
│ ├── Intermediate/ # Partial processing
│ └── Clean/ # Analysis-ready data
└── Results/
├── Tables/ # Regression tables
└── Figures/ # Visualizations
Use letter suffixes (a, b, c) for parallel steps Use number suffixes (1, 2, 3) for sequential substeps
| Task | Preferred Tool | Rationale |
|---|---|---|
| Figures/Visualizations | Python | Better control, publication-quality with matplotlib/seaborn |
| Regression Tables | Stata | More efficient with outreg2/esttab, standard in economics |
| Data Cleaning | Python | Better for large datasets, flexible transformations |
| Panel Regressions | Stata | reghdfe package is gold standard |
#!/usr/bin/env python3
"""
ScriptName.py
Brief description of what this script does.
Input files:
- Data/Raw/input1.csv
- Data/Intermediate/input2.csv
Output files:
- Data/Clean/output.csv (description)
Author: Your Name
Date: YYYY-MM-DD
"""
import pandas as pd
import numpy as np
from pathlib import Path
import matplotlib.pyplot as plt
import seaborn as sns
def get_project_root():
"""Automatically detect the project root directory."""
return Path(__file__).parent.absolute()
def main():
"""Main processing function."""
print("=" * 70)
print("SCRIPT TITLE")
print("=" * 70)
# Setup paths
base_dir = get_project_root()
data_clean_dir = base_dir / ".." / "Data" / "Clean"
# Your code here
print("\n" + "=" * 70)
print("PROCESSING COMPLETE")
print("=" * 70)
if __name__ == "__main__":
main()
Always use this pattern for portability:
def get_project_root():
"""Automatically detect the project root directory."""
return Path(__file__).parent.absolute()
# Then use relative paths
base_dir = get_project_root()
data_raw_dir = base_dir / ".." / "Data" / "Raw"
data_clean_dir = base_dir / ".." / "Data" / "Clean"
data_intermediate_dir = base_dir / ".." / "Data" / "Intermediate"
results_tables_dir = base_dir / ".." / "Results" / "Tables"
results_figures_dir = base_dir / ".." / "Results" / "Figures"
# Create directories if they don't exist
data_intermediate_dir.mkdir(parents=True, exist_ok=True)
# Loading with error handling
if not input_file.exists():
raise FileNotFoundError(f"Input file not found: {input_file}")
try:
df = pd.read_csv(input_file, low_memory=False)
print(f"Loaded {len(df):,} records")
except Exception as e:
print(f"Error reading file: {e}")
return
# Saving with confirmation
df_sorted = df.sort_values(['company', 'year'])
df_sorted.to_csv(output_file, index=False)
print(f"Saved {len(df_sorted):,} records to: {output_file}")
Use consistent formatting for readability:
# Section headers
print("\n" + "=" * 70)
print("DATA PROCESSING")
print("=" * 70)
# Progress with comma formatting
print(f"\nLoaded {len(df):,} records")
print(f" After filtering: {len(df_filtered):,} ({len(df_filtered)/len(df)*100:.1f}%)")
# Summary statistics
print("\n=== SUMMARY ===")
print(f"Total companies: {df['company'].nunique():,}")
print(f"Date range: {df['date'].min()} to {df['date'].max()}")
print(f"Match rate: {match_rate*100:.1f}%")
def clean_company_name(name_str):
"""
Clean and standardize company names for matching.
Parameters:
- name_str: Raw company name string
Returns:
- Cleaned company name (uppercase, no punctuation)
"""
if pd.isna(name_str):
return ""
# Remove common suffixes
name = str(name_str).upper()
name = re.sub(r'\b(INC|CORP|LTD|LLC)\b', '', name)
name = re.sub(r'[^\w\s]', '', name) # Remove punctuation
return name.strip()
# Check for required columns
required_cols = ['company', 'year', 'value']
missing_cols = [col for col in required_cols if col not in df.columns]
if missing_cols:
raise ValueError(f"Missing required columns: {missing_cols}")
# Report data quality
print("\nData Quality Checks:")
print(f" Missing values in key column: {df['key_col'].isna().sum():,}")
print(f" Duplicate records: {df.duplicated().sum():,}")
print(f" Unique companies: {df['company'].nunique():,}")
# Prepare keys
df1['merge_key'] = df1['company'].astype(str).str.strip().str.upper()
df2['merge_key'] = df2['company'].astype(str).str.strip().str.upper()
# Merge with reporting
print(f"\nMerging datasets:")
print(f" Dataset 1: {len(df1):,} records")
print(f" Dataset 2: {len(df2):,} records")
df_merged = df1.merge(df2, on='merge_key', how='inner', indicator=True)
print(f" Merged: {len(df_merged):,} records")
print(f" Match rate: {len(df_merged)/len(df1)*100:.1f}%")
# Check merge results
print("\nMerge indicator breakdown:")
print(df_merged['_merge'].value_counts())
# Setup (at top of script)
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style("whitegrid")
plt.rcParams['figure.figsize'] = (12, 7)
# Create publication-quality figures
fig, ax = plt.subplots(figsize=(14, 8))
ax.plot(x, y, marker='o', linewidth=2, markersize=8,
color='#2E86AB', label='Series Name')
ax.set_xlabel('X-axis Label', fontsize=12, fontweight='bold')
ax.set_ylabel('Y-axis Label', fontsize=12, fontweight='bold')
ax.set_title('Figure Title', fontsize=14, fontweight='bold', pad=20)
# Format y-axis with commas
ax.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'{int(x):,}'))
ax.legend(loc='best', frameon=True, fancybox=True, shadow=True)
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig(output_path, dpi=300, bbox_inches='tight')
plt.close()
print(f"Saved figure to: {output_path}")
| Type | Convention | Examples |
|---|---|---|
| DataFrames | df_ prefix | df, df_filtered, df_merged, df_agg |
| Paths | _dir or _file suffix | base_dir, input_file, output_path |
| Functions | snake_case verbs | clean_data(), load_files(), calculate_returns() |
| Variables | snake_case | company_name, year_founded, total_assets |
| Constants | UPPER_CASE | START_YEAR, MIN_OBSERVATIONS |
/*
================================================================================
ScriptName.do
Description of the analysis performed in this script.
Inputs:
- ../Data/Clean/input_data.csv
Outputs:
- ../Results/Tables/Table1_MainResults.xls
- ../Code/LogFiles/ScriptName.log
Author: Your Name
Date: YYYY-MM-DD
================================================================================
*/
*** Set up paths
global repodir "/Users/zrsong/MIT Dropbox/Zirui Song/Research Projects/PROJECT_NAME"
global datadir "$repodir/Data"
global cleandir "$datadir/Clean"
global intdir "$datadir/Intermediate"
global tabdir "$repodir/Results/Tables"
global figdir "$repodir/Results/Figures"
global logdir "$repodir/Code/LogFiles"
*** Start log
log using "$logdir/ScriptName.log", text replace
/*==============================================================================
Data Preparation
==============================================================================*/
import delimited "$cleandir/input_data.csv", clear
[Your code here]
*** Close log
log close
Always define these at the top:
global repodir "/Full/Path/To/Project"
global datadir "$repodir/Data"
global cleandir "$datadir/Clean"
global intdir "$datadir/Intermediate"
global rawdir "$datadir/Raw"
global tabdir "$repodir/Results/Tables"
global figdir "$repodir/Results/Figures"
global logdir "$repodir/Code/LogFiles"
Note: Update repodir for each user/computer
/*==============================================================================
Main Regressions - Table 1
==============================================================================*/
*** Define variable lists
local borr_controls "log_assets leverage tangibility profitability"
local loan_controls "log_amount maturity"
local all_controls "`borr_controls' `loan_controls'"
*** Column 1: No controls
reghdfe outcome treatment_var, ///
absorb(industry year) ///
vce(cluster firm_id)
outreg2 using "$tabdir/Table1_MainResults.xls", replace excel ///
ctitle("(1) No Controls") label dec(3) ///
addtext(Industry FE, YES, Year FE, YES) ///
keep(treatment_var)
*** Column 2: With controls
reghdfe outcome treatment_var `all_controls', ///
absorb(industry year) ///
vce(cluster firm_id)
outreg2 using "$tabdir/Table1_MainResults.xls", append excel ///
ctitle("(2) Full Controls") label dec(3) ///
addtext(Industry FE, YES, Year FE, YES, Controls, YES) ///
keep(treatment_var `all_controls')
Two output workflows:
| Stage | Command | Output Format | Use Case |
|---|---|---|---|
| Working/Exploratory | outreg2 | Excel (.xls) | Quick iteration, reviewing results |
| Final Paper | esttab | LaTeX (.tex) | Publication-ready tables |
Use outreg2 with the excel option for exploratory analysis and quick iterations:
outreg2 using "$tabdir/TableName.xls", [replace/append] excel ///
ctitle("Column Title") /// // Column header
label /// // Use variable labels
dec(3) /// // 3 decimal places
keep(vars_to_show) /// // Variables to display
addtext(Industry FE, YES, /// // Notes for fixed effects
Year FE, YES, ///
Controls, YES)
Working table naming:
Table1_MainResults.xlsTable2_Robustness.xlsTableA1_DescriptiveStats.xls (appendix)Use esttab to generate publication-ready LaTeX tables:
*** Store regression results
eststo clear
eststo m1: reghdfe outcome treatment, absorb(industry year) vce(cluster firm_id)
eststo m2: reghdfe outcome treatment `controls', absorb(industry year) vce(cluster firm_id)
eststo m3: reghdfe outcome treatment `controls', absorb(firm_id year) vce(cluster firm_id)
*** Output LaTeX table
esttab m1 m2 m3 using "$tabdir/Table1_MainResults.tex", replace ///
b(3) se(3) /// // 3 decimal places for coef and SE
star(* 0.10 ** 0.05 *** 0.01) /// // Significance stars
label /// // Use variable labels
booktabs /// // Professional table formatting
nomtitles /// // No model titles (use column numbers)
mgroups("Dependent Variable: Outcome", pattern(1 0 0) ///
prefix(\multicolumn{@span}{c}{) suffix(}) span erepeat(\cmidrule(lr){@span})) ///
keep(treatment `controls') /// // Variables to display
order(treatment `controls') /// // Variable order
stats(r2 N, fmt(3 0) labels("R-squared" "Observations")) ///
indicate("Industry FE = *industry*" "Year FE = *year*" "Firm FE = *firm_id*") ///
addnotes("Standard errors clustered by firm in parentheses." ///
"* p<0.10, ** p<0.05, *** p<0.01")
Simplified esttab for quick LaTeX output:
esttab m1 m2 m3 using "$tabdir/Table1.tex", replace ///
b(3) se(3) star(* 0.10 ** 0.05 *** 0.01) ///
label booktabs ///
keep(treatment) ///
stats(r2 N, fmt(3 0) labels("R\$^2\$" "N")) ///
addnotes("Clustered SEs in parentheses.")
Final table naming:
Table1_MainResults.texTable2_Robustness.texTableA1_Appendix.tex*** Firm and year fixed effects with clustering
reghdfe outcome treatment controls, ///
absorb(firm_id year) ///
vce(cluster firm_id)
*** Industry and year fixed effects
reghdfe outcome treatment controls, ///
absorb(industry year) ///
vce(cluster firm_id)
*** Fama-French 12 industry classification
sicff sic, ind(12) gen(ff12)
reghdfe outcome treatment controls, ///
absorb(ff12 year) ///
vce(cluster firm_id)
/*==============================================================================
Subsample Analysis - Large Firms
==============================================================================*/
preserve
*** Keep only observations meeting criteria
keep if total_assets > median_assets
*** Run regressions for subsample
reghdfe outcome treatment controls, ///
absorb(industry year) ///
vce(cluster firm_id)
outreg2 using "$tabdir/Table2_Subsamples.xls", append excel ///
ctitle("Large Firms") label dec(3)
restore
*** Generate dummy variables
gen high_leverage = (leverage > 0.3)
replace high_leverage = 0 if missing(high_leverage)
label variable high_leverage "Leverage > 30%"
*** Generate interaction terms
gen treat_x_post = treatment * post
label variable treat_x_post "Treatment × Post"
*** Generate time trends
gen year_trend = year - 2000
gen year_trend_sq = year_trend^2
/*==============================================================================
Table 1: Descriptive Statistics
==============================================================================*/
*** Summary statistics
estpost tabstat outcome treatment control1 control2, ///
statistics(count mean sd min p25 p50 p75 max) ///
columns(statistics)
esttab using "$tabdir/Table1_Descriptives.csv", ///
cells("count mean sd min p25 p50 p75 max") ///
replace noobs nomtitle nonumber
*** Alternative: Use outreg2
outreg2 using "$tabdir/Table1_Descriptives.xls", replace sum(log) ///
keep(outcome treatment control1 control2) ///
eqkeep(N mean sd min max)
/*==============================================================================
Section Title
==============================================================================*/
*** Subsection description
[Code for subsection]
*** Another subsection
[More code]
| Type | Convention | Examples |
|---|---|---|
| Data cleaning | [N]_[Action][Dataset].py | 1a_CleanIPO.py, 2_MergeCompustat.py |
| Analysis | AN_[N]_[Description].[ext] | AN_1_DescriptiveStats.py, AN_2_MainReg.do |
| Data files | Descriptive names | comp_crspa_merged.csv, loan_panel_final.csv |
Before running any script:
After running any script:
Every script must include:
Every analysis must document:
Within a script, follow this order:
if __name__ == "__main__":)# Check before processing
assert df['key'].notna().all(), "Key column has missing values"
assert df['year'].between(1990, 2025).all(), "Year outside expected range"
assert not df.duplicated(subset=['key']).any(), "Duplicate keys found"
# Validate merge results
assert len(df_merged) > 0, "Merge produced no matches"
assert '_merge' in df_merged.columns, "Merge indicator missing"
Always include:
np.random.seed(42)Never:
repodir)Git best practices:
.gitignore for:
__pycache__/
*.pyc
.DS_Store
LogFiles/
*.log
.ipynb_checkpoints/
#!/usr/bin/env python3
"""Brief description."""
import pandas as pd
from pathlib import Path
def get_project_root():
return Path(__file__).parent.absolute()
def main():
# Paths
base_dir = get_project_root()
input_file = base_dir / ".." / "Data" / "Raw" / "input.csv"
output_file = base_dir / ".." / "Data" / "Clean" / "output.csv"
# Load
df = pd.read_csv(input_file)
print(f"Loaded {len(df):,} records")
# Process
df_clean = df.dropna(subset=['key_col'])
df_clean = df_clean[df_clean['year'] >= 2000].copy()
# Save
df_clean.to_csv(output_file, index=False)
print(f"Saved {len(df_clean):,} records")
if __name__ == "__main__":
main()
def merge_datasets(df1, df2, merge_key, how='inner'):
"""Merge with reporting."""
print(f"\nMerging datasets:")
print(f" Left: {len(df1):,} records")
print(f" Right: {len(df2):,} records")
merged = df1.merge(df2, on=merge_key, how=how, indicator=True)
print(f" Result: {len(merged):,} records")
print(f"\nMerge breakdown:")
print(merged['_merge'].value_counts())
return merged
*** Table X: Main Results
local controls "control1 control2 control3"
*** Column 1
reghdfe outcome treatment, absorb(fe1 fe2) vce(cluster id)
outreg2 using "$tabdir/TableX.xls", replace excel ///
ctitle("(1)") label dec(3) ///
addtext(FE1, YES, FE2, YES) keep(treatment)
*** Column 2
reghdfe outcome treatment `controls', absorb(fe1 fe2) vce(cluster id)
outreg2 using "$tabdir/TableX.xls", append excel ///
ctitle("(2)") label dec(3) ///
addtext(FE1, YES, FE2, YES, Controls, YES) keep(treatment `controls')
*** Generate summary statistics
estpost tabstat var1 var2 var3, ///
statistics(count mean sd min max) columns(statistics)
esttab using "$tabdir/Summary.csv", ///
cells("count mean sd min max") replace noobs
SettingWithCopyWarning: Always use .copy() after filtering
df_subset = df[df['year'] >= 2000].copy() # Good
df_subset = df[df['year'] >= 2000] # Bad
Path issues: Use Path objects, not string concatenation
file = base_dir / "Data" / "file.csv" # Good
file = base_dir + "/Data/file.csv" # Bad
Memory issues: Use low_memory=False for large CSV files
df = pd.read_csv(file, low_memory=False)
Path separators: Use forward slashes even on Windows
global dir "C:/Users/Name/Project" // Good
global dir "C:\Users\Name\Project" // Bad
Missing absorb(): Don't forget to include absorb when using reghdfe
reghdfe y x, absorb(fe1 fe2) vce(cluster id) // Good
reghdfe y x, vce(cluster id) // Bad - will error
Log file conflicts: Always use replace option
log using "$logdir/script.log", text replace // Good
log using "$logdir/script.log", text // Bad - will error if exists