A Python package for estimating the Changes-in-Changes model of Athey and Imbens (2006)
Project description
pycinc
A Python package for estimating Changes-in-Changes (CiC) models, as introduced by Athey and Imbens (2006). This approach generalizes standard difference-in-differences (DiD) methods and allows for nonlinear and heterogeneous effects across the outcome distribution.
Installation
Install the package using pip:
pip install pycinc
Features
- 2x2 DiD Design: Implements the simplest two-group, two-period setup
- Quantile Treatment Effects: Estimates how treatment effects vary across the distribution of outcomes
- Nonlinear Effects: Captures effects beyond simple average changes
- Confidence Intervals: Bootstrap-based confidence intervals and standard errors
- Visualization: Built-in plotting of estimated effects and distributions
- Integration with Pandas
Quick Start
import numpy as np
import pandas as pd
from pycinc import ChangesInChanges
# Generate synthetic data
np.random.seed(1988)
n = 1000
# Control group
y_control_before = np.random.normal(10, 2, n)
y_control_after = y_control_before + np.random.normal(1, 0.5, n)
# Treatment group
y_treat_before = np.random.normal(12, 2, n)
y_treat_after = y_treat_before + np.random.normal(1, 0.5, n) + 3 # Treatment effect
# Combine into DataFrame
data = pd.DataFrame({
'outcome': np.concatenate([y_control_before, y_control_after,
y_treat_before, y_treat_after]),
'group': np.concatenate([[0]*n, [0]*n,
[1]*n, [1]*n]),
'period': np.concatenate([[0]*n, [1]*n,
[0]*n, [1]*n])
})
# Fit CiC model
cic = ChangesInChanges()
results = cic.fit(data, outcome='outcome', group='group', period='period')
# View results
print(results.summary())
# Plot treatment effects across quantiles
results.plot()
Examples
You can find detailed usage examples in the examples/ directory.
Background
From Average Effects to Distributional Insights
Traditional difference-in-differences (DiD) methods focus on average treatment effects and rely on the parallel trends assumption—that treated and control groups would have followed similar trends in the absence of treatment. The Changes-in-Changes (CiC) estimator, proposed by Athey and Imbens (2006), relaxes this by allowing for:
- Heterogeneous effects across the distribution of outcomes
- Nonlinear changes rather than additive shifts
- Distributional treatment effects, not just mean effects
This makes CiC especially useful in applications where policy effects may differ between low and high quantiles (e.g. tax credits, training programs, subsidies).
Notation
Let's establish the following mathematical notation:
- $Y_{gt}$ denote the outcome for group $g \in {0,1}$ at time $t \in {0,1}$. Here 1 stands for Treatment and After observations, respectively.
- $F_{gt}$ denote the cumulative distribution function (CDF) of $Y_{gt}$
- $Q_{gt}(u) = F_{gt}^{-1}(u)$ be the corresponding quantile function
- $U \sim \text{Uniform}(0,1)$ represent unobservable rank
Main Result
Athey and Imbens showed that the counterfactual (unobserved) outcome for a treated individual at time 1 (had they not been treated) can be computed as:
$$ Y_{\tilde{11}} = Q_{01}(F_{00}(Y_{10})) $$
Here's what this equation does:
- $Y_{10}$ is the treated unit's outcome before treatment (group 1, time 0).
- $F_{00}(Y_{10})$ finds the rank of that pre-treatment outcome in the control group's pre-treatment distribution.
- $Q_{01}(\cdot)$ maps that rank to the control group's post-treatment distribution (group 0, time 1). The treatment effect for each treated unit is then:
$$ \tau = Y_{11}^{\text{obs}} - Y_{\tilde{11}} $$
Aggregating these effects across quantiles yields the quantile treatment effects (QTEs), allowing you to estimate how treatment affects different parts of the outcome distribution.
Intuition
Put simply, the CiC model (i) finds where the treated individual ranked in the control group before treatment, (ii) sees where someone at that same rank ended up in the control group after treatment, and (iii) uses that as the counterfactual outcome.
Assumptions
The identification strategy relies on the following four assumptions concerning either the data generating process or the joint distribution of $(Y,G,T)$.:
- Model: The outcome in absence of intervention can be expressed as $Y_0=h(U,T)$ for some function $h(\cdot)$.
- Monotonicity: The outcome variable $Y$ is strictly increasing in unobserved heterogeneity $U$. This ensures $h(\cdot)$ is invertible in $U$.
- Time-invariant unobservables: The distribution of unobserved factors $U$ is stable over time within each group, $U\perp T \mid G$. This is indeed the main assumption, requiring difference between units in both groups be stable over time.
- Common support: The supports of outcome distributions overlap across groups and time periods.
To summarize, the key identification assumption is rank invariance of untreated potential outcomes over time: for each unit, the rank (quantile) of their untreated outcome remains constant across periods. Additionally, it assumes the distribution of untreated potential outcomes evolves over time in the same way for treated and control groups.
Confidence Intervals
Because the CiC estimator involves nonparametric transformations of empirical distributions, analytical standard errors are not readily available. Instead, the package provides support for bootstrap confidence intervals, which work as follows:
- Re-sample observations with replacement within each group × time cell.
- Recompute the CiC estimator on each bootstrap sample.
- Use the empirical distribution of bootstrap estimates to form percentile intervals.
This ensures robust inference for both point estimates and quantile treatment effects.
References
- Athey, S., & Imbens, G. W. (2006). Identification and inference in nonlinear difference-in-differences models. Econometrica, 74(2), 431–497.
License
This project is licensed under the MIT License – see the LICENSE file for details.
Citation
To cite this package in publications, use the following BibTeX entry:
@misc{yasenov2025pycinc,
author = {Vasco Yasenov},
title = {pycinc: Python Implementation of the Changes-in-Changes Estimator},
year = {2025},
howpublished = {\url{https://github.com/vyasenov/pycinc}},
note = {Version 0.1.0}
}
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pycinc-0.2.0.tar.gz.
File metadata
- Download URL: pycinc-0.2.0.tar.gz
- Upload date:
- Size: 12.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9cf47452b8b3e7516e202349a1c992bc98efd7dcee6efe9592f72016a7729f0e
|
|
| MD5 |
c5ca4db6ed79cbfad7923b8db55bdf38
|
|
| BLAKE2b-256 |
17a4b6de97bff053cd37433a34aae01da395a589d36c67a2b605ff96c8575dd5
|
File details
Details for the file pycinc-0.2.0-py3-none-any.whl.
File metadata
- Download URL: pycinc-0.2.0-py3-none-any.whl
- Upload date:
- Size: 10.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e8cb95dd7c1aeef8ace835b77bc73af3e36088828190c779430c9bdf29e5129f
|
|
| MD5 |
b31a769f7678813ea8efd6d885fa469a
|
|
| BLAKE2b-256 |
2a40f9765588e8390d56e143226ec7189ec8838baa6e343aaa8f73ad8ea32078
|