Skip to main content

Synthetic Difference-in-Differences (SDID) for causal inference in Python

Reason this release was yanked:

Buggy SDID estimator (degenerate time weights). Upgrade to 0.4.0.

Project description

Synthetic Difference-in-Differences (SDID)

PyPI version Python 3.10+ License: MIT Ruff

English | 繁體中文


English

A Python implementation of Synthetic Difference-in-Differences for causal inference.

Overview

SDID combines synthetic control methods with difference-in-differences to provide robust causal effect estimates. It automatically finds optimal weights for:

  • Control units: Creates a synthetic comparison group
  • Time periods: Balances pre/post treatment comparisons

Installation

From PyPI (Recommended)

pip install sdid

From Source

git clone https://github.com/yourusername/sdid.git
cd sdid
pip install .

Development Installation

git clone https://github.com/yourusername/sdid.git
cd sdid
uv sync --extra dev

Quick Start

import pandas as pd
from sdid import SyntheticDiffInDiff

# Load your panel data
data = pd.read_csv("your_data.csv")

# Initialize and fit
sdid = SyntheticDiffInDiff(
    data=data,
    outcome_col="outcome",
    times_col="year",
    units_col="state",
    treat_col="treated",
    post_col="post"
)

# Estimate treatment effect
effect = sdid.fit()
print(f"Treatment Effect: {effect:.4f}")

# Estimate standard error
sdid.estimate_se(n_bootstrap=200, n_jobs=4)
print(sdid.summary())

Data Format

Your data should be in long format (one row per unit-time observation):

Column Description Example
outcome Outcome variable Sales, GDP
times Time period 2018, 2019, 2020
units Unit identifier "CA", "TX", "NY"
treat Treatment indicator 0 = control, 1 = treated
post Post-treatment period 0 = before, 1 = after

Example:

unit  year  outcome  treated  post
CA    2018  100.5    0        0
CA    2019  102.3    0        0
CA    2020  105.1    0        1
TX    2018  98.2     1        0
TX    2019  99.8     1        0
TX    2020  108.7    1        1

API Reference

Method Description
fit(verbose=False) Fit model and return treatment effect
estimate_se(n_bootstrap, seed, n_jobs) Estimate standard error via placebo bootstrap
summary() Return formatted results summary
run_event_study(times) Estimate effects for multiple periods
plot_event_study(times, ...) Create event study plot with confidence intervals
get_weights_summary() Return unit and time weights
is_fitted Property to check if model is fitted

Event Study

# Estimate dynamic treatment effects
effects = sdid.run_event_study([2020, 2021, 2022])

# Plot with confidence intervals
fig = sdid.plot_event_study(
    times=[2020, 2021, 2022],
    n_bootstrap=200,
    confidence_level=0.95,
    n_jobs=4
)
fig.savefig("event_study.png", dpi=300)

Assumptions

SDID relies on these key assumptions:

  1. No anticipation: Units don't change behavior before treatment
  2. SUTVA: No spillover effects between units
  3. Overlap: Control units can approximate treated units

Reference

@article{arkhangelsky2021synthetic,
  title={Synthetic difference-in-differences},
  author={Arkhangelsky, Dmitry and Athey, Susan and Hirshberg, David A and Imbens, Guido W and Wager, Stefan},
  journal={American Economic Review},
  volume={111},
  number={12},
  pages={4088--4118},
  year={2021}
}

Development

# Install dev dependencies
uv sync --extra dev

# Run tests
uv run pytest tests/ -v

# Run linter
uv run ruff check .

# Format code
uv run ruff format .

# Build package
uv build

# Upload to PyPI (requires API token)
uv publish

License

MIT License - see LICENSE for details.


繁體中文

合成雙重差分法 (SDID) 的 Python 實現,用於因果推論。

概述

SDID 結合了合成控制法與雙重差分法的優點,提供穩健的因果效應估計。它自動計算最佳權重:

  • 控制單位權重:建立合成對照組
  • 時間期間權重:平衡處理前後的比較

安裝

從 PyPI 安裝(推薦)

pip install sdid

從原始碼安裝

git clone https://github.com/yourusername/sdid.git
cd sdid
pip install .

開發安裝

git clone https://github.com/yourusername/sdid.git
cd sdid
uv sync --extra dev

快速開始

import pandas as pd
from sdid import SyntheticDiffInDiff

# 載入面板資料
data = pd.read_csv("your_data.csv")

# 初始化並擬合
sdid = SyntheticDiffInDiff(
    data=data,
    outcome_col="outcome",    # 結果變數
    times_col="year",         # 時間
    units_col="state",        # 單位識別
    treat_col="treated",      # 處理指標
    post_col="post"           # 處理後指標
)

# 估計處理效果
effect = sdid.fit()
print(f"處理效果: {effect:.4f}")

# 估計標準誤
sdid.estimate_se(n_bootstrap=200, n_jobs=4)
print(sdid.summary())

資料格式

資料須為長格式(每個單位-時間組合一列):

欄位 說明 範例
outcome 結果變數 銷售額、GDP
times 時間期間 2018, 2019, 2020
units 單位識別 "CA", "TX", "NY"
treat 處理指標 0 = 控制組, 1 = 處理組
post 處理後期間 0 = 處理前, 1 = 處理後

範例:

unit  year  outcome  treated  post
CA    2018  100.5    0        0
CA    2019  102.3    0        0
CA    2020  105.1    0        1
TX    2018  98.2     1        0
TX    2019  99.8     1        0
TX    2020  108.7    1        1

API 參考

方法 說明
fit(verbose=False) 擬合模型並回傳處理效果
estimate_se(n_bootstrap, seed, n_jobs) 透過安慰劑 bootstrap 估計標準誤
summary() 回傳格式化的結果摘要
run_event_study(times) 估計多個時間點的效果
plot_event_study(times, ...) 繪製帶信賴區間的事件研究圖
get_weights_summary() 回傳單位和時間權重
is_fitted 檢查模型是否已擬合的屬性

事件研究

# 估計動態處理效果
effects = sdid.run_event_study([2020, 2021, 2022])

# 繪製帶信賴區間的圖表
fig = sdid.plot_event_study(
    times=[2020, 2021, 2022],
    n_bootstrap=200,
    confidence_level=0.95,
    n_jobs=4
)
fig.savefig("event_study.png", dpi=300)

假設條件

SDID 依賴以下關鍵假設:

  1. 無預期效應:單位不會在處理前改變行為
  2. SUTVA:單位間無外溢效應
  3. 重疊性:控制單位能近似處理單位

參考文獻

@article{arkhangelsky2021synthetic,
  title={Synthetic difference-in-differences},
  author={Arkhangelsky, Dmitry and Athey, Susan and Hirshberg, David A and Imbens, Guido W and Wager, Stefan},
  journal={American Economic Review},
  volume={111},
  number={12},
  pages={4088--4118},
  year={2021}
}

開發

# 安裝開發相依套件
uv sync --extra dev

# 執行測試
uv run pytest tests/ -v

# 執行 linter
uv run ruff check .

# 格式化程式碼
uv run ruff format .

# 建置套件
uv build

# 上傳到 PyPI(需要 API token)
uv publish

授權

MIT 授權 - 詳見 LICENSE

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sdid-0.1.0.tar.gz (16.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sdid-0.1.0-py3-none-any.whl (12.8 kB view details)

Uploaded Python 3

File details

Details for the file sdid-0.1.0.tar.gz.

File metadata

  • Download URL: sdid-0.1.0.tar.gz
  • Upload date:
  • Size: 16.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.22

File hashes

Hashes for sdid-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b43ec942cb91779d8548e5d63b86ec3d78e27dbcc5afec688fad9ae31e92cdff
MD5 3d4b6dde00c0a9b04e384e80bcf2796c
BLAKE2b-256 e0303ad9957d3b031c5c4d0a675956aff71945498c5a46b2b29111c5e8e5ad1a

See more details on using hashes here.

File details

Details for the file sdid-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: sdid-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 12.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.22

File hashes

Hashes for sdid-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5d947ad95d165f370a245e9bd3a79042c3c3459e9f3c1d232970e05a6ab801ca
MD5 0959d9b81a892c9762d34b93cc0cc88f
BLAKE2b-256 6b984ab63d747d52023b4f7b33ea8517133a9962f83eaca1210890ed07859e2c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page