Results Module
Container class for difference-in-differences estimation outputs.
This module provides the LWDIDResults class for encapsulating estimation
outputs from both common timing and staggered adoption DiD designs. The
container stores point estimates, standard errors, confidence intervals,
period-specific effects, and diagnostic information. Multiple export formats
are supported for reproducible research and integration with statistical
reporting workflows.
The LWDIDResults object is returned by the main lwdid.lwdid()
function and provides a unified interface for accessing estimation outputs
regardless of whether the design uses common timing or staggered adoption.
For staggered designs, additional attributes provide cohort-specific and
cohort-time specific effect estimates.
Result container for difference-in-differences estimation outputs.
This module provides the LWDIDResults class for encapsulating estimation outputs from rolling transformation DiD methodology, supporting three scenarios:
Small-sample common timing: Results include exact t-based inference statistics under classical linear model assumptions.
Large-sample common timing: Results include asymptotic inference with heteroskedasticity-robust standard errors.
Staggered adoption: Results include cohort-time specific effects, cohort-level aggregations, and overall weighted effects with flexible control group strategies.
The class implements immutable core attributes via properties to ensure result integrity, provides multiple summary formats (text, LaTeX, Excel, CSV), supports event study visualization for staggered designs, and includes period-specific effects for common timing designs.
Attributes Reference
The LWDIDResults object provides read-only access to estimation outputs
through properties. Attributes are organized into categories based on their
purpose.
Core Estimates
These attributes provide the primary treatment effect estimates and inference statistics.
att(float): Average treatment effect on the treated (ATT).se_att(float): Standard error of ATT.t_stat(float): t-statistic for H0: ATT = 0.pvalue(float): Two-sided p-value for the t-test.ci_lower(float): Lower bound of 95% confidence interval.ci_upper(float): Upper bound of 95% confidence interval.
Sample Information
These attributes describe the estimation sample.
nobs(int): Number of observations in the regression.n_treated(int): Number of treated units in the sample.n_control(int): Number of control units in the sample.K(int): Last pre-treatment period index.tpost1(int): First post-treatment period index.
Inference Configuration
These attributes describe the variance estimation and inference settings.
df_resid(int): Residual degrees of freedom from the regression.df_inference(int): Degrees of freedom used for inference. For cluster-robust SE, this is G - 1; otherwise equalsdf_resid.vce_type(str or None): Variance estimator: ‘ols’, ‘hc0’, ‘robust’/’hc1’, ‘hc2’, ‘hc3’, ‘hc4’, or ‘cluster’.cluster_var(str or None): Clustering variable name (ifvce='cluster').n_clusters(int or None): Number of clusters (ifvce='cluster').
Transformation and Controls
These attributes describe the transformation method and control variables used.
rolling(str): Transformation method: ‘demean’, ‘detrend’, ‘demeanq’, or ‘detrendq’.controls_used(bool): Whether control variables were included.controls(list): List of control variable names used.
Period-Specific Effects
att_by_period(pd.DataFrame or None): Period-specific ATT estimates with columns: period, tindex, beta, se, ci_lower, ci_upper, tstat, pval, N. First row contains the overall average effect.
Randomization Inference
These attributes are available only when ri=True is specified in the
lwdid() call.
ri_pvalue(float or None): Randomization inference p-value.ri_seed(int or None): Random seed used for RI.rireps(int or None): Number of RI replications.ri_method(str or None): RI method: ‘bootstrap’ or ‘permutation’.ri_valid(int or None): Number of valid (successful) RI replications.ri_failed(int or None): Number of failed RI replications.
Regression Coefficients
These attributes provide access to the full regression output.
params(array-like): Full vector of regression coefficients.bse(array-like): Standard errors of all coefficients.vcov(array-like): Variance-covariance matrix.
Staggered-Specific Attributes
These attributes are available only for staggered adoption designs (when
gvar is specified instead of post).
Design Information:
is_staggered(bool): Whether this is a staggered DiD design.cohorts(list): Sorted list of treatment cohorts (first treatment periods).cohort_sizes(dict): Number of units in each cohort.n_never_treated(int or None): Number of never-treated units.control_group(str or None): User-specified control group strategy.control_group_used(str or None): Actual control group strategy used (may differ due to auto-switching).aggregate(str or None): Aggregation level: ‘none’, ‘cohort’, or ‘overall’.estimator(str or None): Estimation method: ‘ra’, ‘ipw’, ‘ipwra’, or ‘psm’.
Effect Estimates:
att_by_cohort_time(pd.DataFrame or None): (g,r)-specific ATT estimates with columns: cohort, period, event_time, att, se, ci_lower, ci_upper, t_stat, pvalue, n_treated, n_control.att_by_cohort(pd.DataFrame or None): Cohort-specific ATT estimates (ifaggregate='cohort'or'overall').att_overall(float or None): Overall weighted ATT (ifaggregate='overall').se_overall(float or None): Standard error of overall ATT.ci_overall_lower(float or None): 95% CI lower bound for overall ATT.ci_overall_upper(float or None): 95% CI upper bound for overall ATT.t_stat_overall(float or None): t-statistic for overall ATT.pvalue_overall(float or None): p-value for overall ATT.cohort_weights(dict): Cohort weights for overall effect (\(\omega_g = N_g / N_{treat}\)).
Methods Reference
Display Methods
- summary()
Generate a formatted summary of estimation results. For staggered designs, automatically dispatches to
summary_staggered(). Returns a string suitable for console output.print(results.summary())
- summary_staggered()
Generate a formatted summary for staggered DiD results. Displays treatment cohorts, sample sizes, control group strategy, overall weighted effect (if
aggregate='overall'), and cohort-specific effects. Raises ValueError if called on non-staggered results.
Visualization Methods
- plot(gid=None, graph_options=None)
Generate a time series plot of residualized outcomes for treated and control groups. A vertical line indicates the treatment start period.
Parameters:
gid(str or int, optional): Specific unit ID to highlight.graph_options(dict, optional): Matplotlib customization options.
Returns: matplotlib.figure.Figure
fig = results.plot() fig.savefig('trends.png')
- plot_event_study(…)
Generate an event study diagram for staggered DiD results. Aggregates cohort-time specific effects by event time (e = r - g) and visualizes dynamic treatment effects relative to a reference period.
Key parameters:
ref_period(int, optional): Reference period for normalization. Default 0.show_ci(bool): Display 95% confidence interval shading. Default True.aggregation({‘mean’, ‘weighted’}): Cross-cohort aggregation method.include_pre_treatment(bool): Include pre-treatment periods. Default True.return_data(bool): Also return the aggregated event study DataFrame.
Returns: (fig, ax) or (fig, ax, event_df) if
return_data=True.fig, ax = results.plot_event_study( title='Policy Effect', ylabel='Treatment Effect' ) fig.savefig('event_study.png', dpi=300)
Export Methods
- to_excel(path)
Export results to an Excel file with multiple sheets. For common timing: Summary sheet with core statistics, ByPeriod sheet with period-specific effects, and RI sheet if randomization inference was performed. For staggered designs: Summary, Overall, Cohort, CohortTime, Weights, and Metadata sheets.
results.to_excel('results.xlsx')
- to_csv(path)
Export period-specific effects (
att_by_period) to CSV format.results.to_csv('period_effects.csv')
- to_latex(path)
Export results to a LaTeX table file. Generates publication-ready tables containing summary statistics and period-specific effects.
results.to_latex('table.tex')
Usage by Design Type
Common Timing Design
For common timing designs (specified with the post parameter), the
following attributes are available:
from lwdid import lwdid
results = lwdid(data, y='outcome', d='treated', ivar='unit',
tvar='year', post='post', rolling='detrend')
# Core estimates
print(f"ATT: {results.att:.4f}")
print(f"SE: {results.se_att:.4f}")
print(f"t-stat: {results.t_stat:.3f}")
print(f"p-value: {results.pvalue:.4f}")
print(f"95% CI: [{results.ci_lower:.4f}, {results.ci_upper:.4f}]")
# Sample information
print(f"N = {results.nobs}, df = {results.df_inference}")
print(f"Treated: {results.n_treated}, Control: {results.n_control}")
# Period-specific effects
print(results.att_by_period)
# Staggered-specific attributes are None
assert results.is_staggered == False
assert results.att_overall is None
Staggered Adoption Design
For staggered adoption designs (specified with the gvar parameter),
additional attributes are available:
from lwdid import lwdid
results = lwdid(data, y='outcome', ivar='unit', tvar='year',
gvar='first_treat_year', rolling='demean',
aggregate='overall', control_group='not_yet_treated')
# Staggered design indicator
assert results.is_staggered == True
# Overall weighted effect (when aggregate='overall')
print(f"Overall ATT: {results.att_overall:.4f}")
print(f"SE: {results.se_overall:.4f}")
print(f"95% CI: [{results.ci_overall_lower:.4f}, {results.ci_overall_upper:.4f}]")
# Cohort information
print(f"Cohorts: {results.cohorts}")
print(f"Cohort sizes: {results.cohort_sizes}")
print(f"Cohort weights: {results.cohort_weights}")
# Cohort-specific effects (when aggregate='cohort' or 'overall')
print(results.att_by_cohort)
# (g,r)-specific effects (always available)
print(results.att_by_cohort_time)
# Control group information
print(f"Control group requested: {results.control_group}")
print(f"Control group used: {results.control_group_used}")
# Event study visualization
fig, ax = results.plot_event_study()
Attribute Availability Summary
The following table summarizes attribute availability by design type:
att: Common timing = Yes, Staggered = Yesse_att: Common timing = Yes, Staggered = Yesatt_by_period: Common timing = Yes, Staggered = Nois_staggered: Common timing = False, Staggered = Trueatt_overall: Common timing = No, Staggered = whenaggregate='overall'att_by_cohort: Common timing = No, Staggered = whenaggregate='cohort'or'overall'att_by_cohort_time: Common timing = No, Staggered = Yes (always)cohorts: Common timing = Empty list, Staggered = Yescohort_weights: Common timing = Empty dict, Staggered = Yes
LWDIDResults Class
- class lwdid.results.LWDIDResults(results_dict, metadata, att_by_period=None, cohort_time_effects=None)[source]
Bases:
objectContainer for difference-in-differences estimation results.
Stores all estimation outputs from the lwdid() function implementing the rolling transformation methodology. Supports three scenarios:
Small-sample common timing: Exact t-based inference under classical linear model assumptions.
Large-sample common timing: Asymptotic inference with heteroskedasticity-robust standard errors.
Staggered adoption: Cohort-time specific effects with flexible control group strategies.
All core attributes are read-only properties to ensure result integrity. Provides methods for displaying, visualizing, and exporting results.
- Variables:
att (float) – Average treatment effect on the treated (ATT) point estimate.
se_att (float) – Standard error of ATT.
t_stat (float) – t-statistic for H0: ATT = 0.
pvalue (float) – Two-sided p-value for t-test.
ci_lower (float) – Lower bound of 95% confidence interval.
ci_upper (float) – Upper bound of 95% confidence interval.
nobs (int) – Number of observations in the regression.
n_treated (int) – Number of treated units.
n_control (int) – Number of control units.
K (int) – Last pre-treatment period index.
tpost1 (int) – First post-treatment period index.
df_resid (int) – Residual degrees of freedom from the main regression.
df_inference (int) – Degrees of freedom used for inference. For cluster-robust standard errors, this is G - 1 (number of clusters minus 1). For other variance estimators, this equals df_resid.
rolling (str) – Transformation method used (‘demean’, ‘detrend’, ‘demeanq’, or ‘detrendq’).
vce_type (str) – Variance estimator type (‘ols’, ‘robust’, ‘hc1’, ‘hc3’, or ‘cluster’).
cluster_var (str or None) – Clustering variable name (if vce=’cluster’).
n_clusters (int or None) – Number of clusters (if vce=’cluster’).
controls_used (bool) – Whether control variables were included.
controls (list) – List of control variable names used.
params (array-like) – Full vector of regression coefficients.
bse (array-like) – Standard errors of all coefficients.
vcov (array-like) – Variance-covariance matrix.
att_by_period (pd.DataFrame) – Period-specific ATT estimates with columns: period, tindex, beta, se, ci_lower, ci_upper, tstat, pval, N.
ri_pvalue (float or None) – Randomization inference p-value (if ri=True was specified).
ri_seed (int or None) – Random seed used for RI.
rireps (int or None) – Number of RI permutations.
ri_method (str or None) – Randomization inference method used (‘bootstrap’ or ‘permutation’). Only available if ri=True was specified.
ri_valid (int or None) – Number of valid (successful) RI replications. Only available if ri=True.
ri_failed (int or None) – Number of failed RI replications. Only available if ri=True.
data (pd.DataFrame) – Transformed data used for regression. Contains the rolling-transformed outcome variable and other regression variables. If the original ivar was string type, this DataFrame contains numeric IDs (1, 2, 3, …). The mapping between original and numeric IDs is stored in data.attrs[‘id_mapping’].
is_staggered (bool) – Whether this is a staggered DiD estimation.
cohorts (list of int) – Sorted list of treatment cohorts (first treatment periods). Only available when is_staggered=True.
cohort_sizes (dict) – Number of units in each cohort. Only available when is_staggered=True.
att_by_cohort_time (pd.DataFrame or None) – (g,r)-specific ATT estimates with columns: cohort, period, event_time, att, se, ci_lower, ci_upper, t_stat, pvalue, n_treated, n_control. Only available when is_staggered=True.
att_by_cohort (pd.DataFrame or None) – Cohort-specific ATT estimates (if aggregate=’cohort’ or ‘overall’). Only available when is_staggered=True.
att_overall (float or None) – Overall weighted ATT (if aggregate=’overall’). Only available when is_staggered=True.
se_overall (float or None) – Standard error of overall ATT. Only available when is_staggered=True.
cohort_weights (dict) – Cohort weights used for overall effect (omega_g = N_g / N_treat). Only available when is_staggered=True.
control_group (str or None) – User-specified control group strategy. Only available when is_staggered=True.
control_group_used (str or None) – Actual control group strategy used (may differ due to auto-switching). Only available when is_staggered=True.
aggregate (str or None) – Aggregation level (‘none’, ‘cohort’, ‘overall’). Only available when is_staggered=True.
estimator (str or None) – Estimation method (‘ra’, ‘ipw’, ‘ipwra’, ‘psm’). Only available when is_staggered=True.
- summary()[source]
Returns formatted results summary string.
- plot(gid=None, graph_options=None)[source]
Generates plot of residualized outcomes (control vs. treated).
- plot_event_study(**kwargs)[source]
Generates event study diagram for staggered designs.
- to_excel(path)[source]
Exports results to Excel file with multiple sheets.
- to_csv(path)[source]
Exports period-specific effects to CSV.
- to_latex(path)[source]
Exports results to LaTeX table format.
See also
lwdidMain estimation function that produces LWDIDResults objects.
- __init__(results_dict, metadata, att_by_period=None, cohort_time_effects=None)[source]
Initialize LWDIDResults container with estimation outputs.
- Parameters:
results_dict (dict) – Estimation results containing keys: ‘att’, ‘se_att’, ‘t_stat’, ‘pvalue’, ‘ci_lower’, ‘ci_upper’, ‘nobs’, ‘df_resid’, ‘params’, ‘bse’, ‘vcov’, ‘resid’, ‘vce_type’.
metadata (dict) – Metadata containing keys: ‘K’, ‘tpost1’, ‘depvar’, ‘N_treated’, ‘N_control’.
att_by_period (pd.DataFrame, optional) – Period-specific effect estimates for common timing design.
cohort_time_effects (list, optional) – List of CohortTimeEffect objects for staggered designs.
- property att: float
ATT point estimate.
- property se_att: float
Standard error of ATT.
- property t_stat: float
t-statistic for ATT.
- property pvalue: float
Two-sided p-value.
- property ci_lower: float
95% CI lower bound.
- property ci_upper: float
95% CI upper bound.
- property nobs: int
Number of observations.
- property n_treated: int
Number of treated units.
- property n_control: int
Number of control units.
- property df_resid: int
Residual degrees of freedom.
- property df_inference: int
Degrees of freedom for inference.
- property K: int
Last pre-treatment period index.
- property tpost1: int
First post-treatment period index.
- property cmd: str
Command name.
- property depvar: str
Dependent variable name.
- property rolling: str
Transformation method used.
- property controls_used: bool
Whether control variables were included.
- property controls: list
List of control variable names.
- property params
Full coefficient vector.
- property bse
Standard errors of coefficients.
- property vcov
Variance-covariance matrix.
- property att_by_period: DataFrame | None
Period-specific ATT estimates (returns copy).
- property data: DataFrame | None
Transformed data used for regression.
- property is_staggered: bool
Whether this is a staggered DiD estimation.
- property cohorts: list
List of treatment cohorts.
- property cohort_sizes: dict
Number of units in each cohort.
- property att_by_cohort_time: DataFrame | None
Cohort-time specific ATT estimates (returns copy).
- property att_by_cohort: DataFrame | None
Cohort-specific ATT estimates (returns copy).
- property cohort_weights: dict
Cohort weights for overall effect.
- property att_pre_treatment: DataFrame | None
Pre-treatment ATT estimates (returns copy).
DataFrame with columns: cohort, period, event_time, att, se, ci_lower, ci_upper, t_stat, pvalue, n_treated, n_control, is_anchor, rolling_window_size.
Only available when include_pretreatment=True was specified during estimation.
- property parallel_trends_test: ParallelTrendsTestResult | None
Parallel trends test results.
Contains individual t-tests for each pre-treatment period and joint F-test for H0: all pre-treatment ATT = 0.
Only available when include_pretreatment=True and pretreatment_test=True were specified during estimation.
- property include_pretreatment: bool
Whether pre-treatment dynamics were computed.
- summary()[source]
Generate a formatted summary of estimation results.
For staggered designs, dispatches to summary_staggered(). For common timing designs, displays ATT estimate, standard error, t-statistic, p-value, confidence interval, and period-specific effects if available.
- Returns:
Formatted results summary string suitable for console output.
- Return type:
- summary_staggered()[source]
Generate a formatted summary for staggered DiD estimation results.
Displays treatment cohorts, sample sizes, control group strategy, overall weighted effect (if aggregate=’overall’), and cohort-specific effects (if aggregate=’cohort’ or ‘overall’).
- Returns:
Formatted results summary string suitable for console output.
- Return type:
- Raises:
ValueError – If called on non-staggered estimation results.
Notes
The summary output varies by aggregation level. When aggregate=’none’, only (g,r)-specific effects are available. When aggregate=’cohort’, cohort-specific effects are shown. When aggregate=’overall’, both cohort-specific and overall weighted effects are displayed. If the control group strategy was automatically switched from the user-specified value, a notification is included.
- plot(gid=None, graph_options=None)[source]
Generate a plot of residualized outcomes for treated and control groups.
Creates a time series plot comparing the average residualized outcomes between treated and control units across all time periods. A vertical line indicates the treatment start period.
- Parameters:
- Returns:
The generated matplotlib figure object.
- Return type:
- Raises:
ValueError – If results.data is not set (plotting requires transformed data).
See also
plot_event_studyEvent study visualization for staggered designs.
- plot_event_study(ref_period=0, show_ci=True, aggregation='mean', include_pre_treatment=True, alpha=0.05, df_strategy='conservative', title=None, xlabel=None, ylabel=None, figsize=(10, 6), savefig=None, dpi=150, ax=None, return_data=False, **kwargs)[source]
Generate an event study diagram for staggered DiD results.
Aggregates cohort-time specific effects by event time (e = r - g) and visualizes dynamic treatment effects relative to a reference period.
- Parameters:
ref_period (int or None, optional) – Reference period for normalization (event time). Default is 0 (first treatment period). If None, no normalization is performed.
show_ci (bool, optional) – Whether to display confidence interval shading. Default True.
aggregation ({'mean', 'weighted'}, optional) – Cross-cohort aggregation method. ‘mean’ computes simple average with SE = sqrt(sum(se^2))/n. ‘weighted’ uses cohort weights with SE = sqrt(sum(w^2 * se^2)). Default ‘mean’.
include_pre_treatment (bool, optional) – Whether to include pre-treatment periods (e < 0). Default True.
alpha (float, optional) – Significance level for confidence intervals. Default 0.05 (95% CI).
df_strategy ({'conservative', 'weighted', 'fallback'}, optional) – Strategy for selecting degrees of freedom for t-distribution: - ‘conservative’: min(df_g) across cohorts (default) - ‘weighted’: weighted average of df_g - ‘fallback’: n_cohorts - 1
title (str, optional) – Plot title. Default ‘Event Study: Dynamic Treatment Effects’.
xlabel (str, optional) – X-axis label. Default ‘Event Time (Periods Since Treatment)’.
ylabel (str, optional) – Y-axis label. Default ‘Treatment Effect’.
figsize (tuple of int, optional) – Figure size in inches (width, height). Default (10, 6).
savefig (str, optional) – File path to save the figure. If provided, saves automatically.
dpi (int, optional) – Resolution for saved figure. Default 150.
ax (matplotlib.axes.Axes, optional) – Existing axes object to plot on. If None, creates new figure.
return_data (bool, optional) – If True, also returns the aggregated event study DataFrame. Default False.
**kwargs – Additional keyword arguments passed to matplotlib plotting functions.
- Returns:
fig (matplotlib.figure.Figure) – The matplotlib figure object.
ax (matplotlib.axes.Axes) – The matplotlib axes object.
event_df (pd.DataFrame) – Aggregated event study data. Only returned if return_data=True.
- Raises:
ValueError – If called on non-staggered results or if att_by_cohort_time is empty or None.
Notes
Confidence intervals use t-distribution rather than normal distribution for proper small-sample inference. The degrees of freedom are selected based on the df_strategy parameter.
See also
plotResidualized outcomes plot for common timing designs.
- to_excel(path)[source]
Export estimation results to an Excel file.
For common timing designs, creates a workbook with Summary sheet containing ATT, SE, t-statistic, p-value, CI bounds, and sample sizes. If period-specific effects are available, includes a ByPeriod sheet. For staggered designs, dispatches to to_excel_staggered().
- Parameters:
path (str) – File path for the Excel output (.xlsx extension recommended).
See also
to_csvExport period-specific effects to CSV format.
to_latexExport results to LaTeX table format.
- to_excel_staggered(path)[source]
Export staggered DiD results to a multi-sheet Excel file.
Creates an Excel workbook with sheets tailored to the aggregation level. The Summary sheet is always included. Additional sheets depend on the aggregate parameter used during estimation.
- Parameters:
path (str) – File path for the Excel output (.xlsx extension required).
- Raises:
ValueError – If called on non-staggered estimation results.
ImportError – If openpyxl package is not installed.
Notes
Sheet structure varies by aggregation level:
aggregate=’overall’: Summary, Overall, Cohort, CohortTime, Weights, Metadata
aggregate=’cohort’: Summary, Cohort, CohortTime, Weights, Metadata
aggregate=’none’: Summary, CohortTime, Metadata
- to_csv(path)[source]
Export period-specific treatment effects to a CSV file.
- Parameters:
path (str) – File path for the CSV output.
- Raises:
ValueError – If att_by_period is not available (None or empty DataFrame).
See also
to_excelExport comprehensive results to Excel format.
- to_latex(path)[source]
Export estimation results to a LaTeX table file.
Generates a LaTeX document containing summary statistics (ATT, SE, t-statistic, p-value, CI bounds, sample sizes) and period-specific effects if available.
- Parameters:
path (str) – File path for the LaTeX output (.tex extension recommended).
See also
to_excelExport comprehensive results to Excel format.
to_csvExport period-specific effects to CSV format.
Example Usage
Basic Example
from lwdid import lwdid
# Run estimation
results = lwdid(data, y='outcome', d='treated', ivar='unit',
tvar='year', post='post', rolling='detrend')
# Display summary
print(results.summary())
# Access attributes
print(f"ATT: {results.att:.4f} (SE: {results.se_att:.4f})")
print(f"95% CI: [{results.ci_lower:.4f}, {results.ci_upper:.4f}]")
# Export results
results.to_excel('results.xlsx')
Staggered Design Example
from lwdid import lwdid
# Estimate with staggered design
results = lwdid(data, y='lhomicide', ivar='state', tvar='year',
gvar='effyear', rolling='demean',
aggregate='overall', control_group='not_yet_treated')
# Display staggered-specific summary
print(results.summary())
# Access overall effect
print(f"Overall ATT: {results.att_overall:.4f}")
# Access cohort-level effects
print(results.att_by_cohort)
# Generate event study plot
fig, ax = results.plot_event_study()
fig.savefig('event_study.png')
# Export with all sheets
results.to_excel('staggered_results.xlsx')
See Also
lwdid.lwdid(): Main estimation function that produces LWDIDResults objects.User Guide : Comprehensive usage guide.
Quick Start : Quick start tutorial.
Staggered DiD Module (staggered) : Staggered module API for low-level access.