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.2.0.tar.gz (16.8 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.2.0-py3-none-any.whl (13.5 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for sdid-0.2.0.tar.gz
Algorithm Hash digest
SHA256 62c81c8d664635fc1bd52f78ffc2db80d760630fa11759b0fe4ef5ebc92fe29b
MD5 6b008d53aece9a8e2c284da937d39598
BLAKE2b-256 d54cd65a71a9146f6f407a07a042a7ead9f1ef7677358db9a1012501359e0202

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for sdid-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 eae4c6f9bb3a9221087377beddb620252c08691041bb2eeed78b6602778a904f
MD5 63e22271e3de8c7e3f4cd29afe9bf10b
BLAKE2b-256 98dccc4919114f940da58d76dbcbcccb2b9f521f63fedc9ac5931f50bf45688c

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