Randomization-based experimental design and causal inference, sklearn-style.
Project description
skxperiments
Randomization-based experimental design and causal inference, sklearn-style.
A Python library for designing randomized experiments and estimating causal effects under the potential outcomes framework (Rubin Causal Model). Treatment assignment is the starting point; statistical models come second.
Status
The v1 feature set is complete: Phases 0–7 are done (sequential testing is deferred to v2). See Project status below for details.
Installation
pip install skxperiments
Requires Python 3.10+. Dependencies: numpy, pandas, scipy.
Quick start
import numpy as np
import pandas as pd
from skxperiments.design.crd import CRD
from skxperiments.estimators.difference_in_means import DifferenceInMeans
from skxperiments.inference import RandomizationTest
# 1. Generate a synthetic dataset
rng = np.random.default_rng(42)
df = pd.DataFrame({
"x": rng.normal(0.0, 1.0, 200),
"y": rng.normal(0.0, 1.0, 200),
})
# 2. Design: completely randomized assignment, 50/50 split
design = CRD(p=0.5, seed=42)
assignment = design.randomize(df)
# 3. Point estimate of the ATE
estimator = DifferenceInMeans(outcome_col="y")
result = estimator.fit(assignment).estimate()
print(result.ate)
# 4. Randomization-based p-value (Fisher's sharp null)
rt = RandomizationTest(estimator=estimator, n_permutations=10_000, seed=0)
result = rt.fit(assignment).estimate()
print(result.ate, result.p_value)
For variance reduction with covariates, use LinEstimator (Lin 2013) or CUPED (Deng et al.
2013). For blocked or factorial designs, use BlockedCRD + BlockedDifferenceInMeans or
FactorialDesign + FactorialEstimator. For rerandomization on Mahalanobis distance,
use ReRandomizedCRD (Morgan & Rubin 2012). RandomizationTest works with all of these
(except FactorialAssignment in v1). To control the family-wise error rate or false
discovery rate when reporting multiple effects, wrap the result in
MultipleTestingCorrection.
Documentation and tutorials
Learning-path notebooks (bilingual, Portuguese and English) live in
examples/for_starters/; conceptual docs (a glossary
and a "how to choose" guide) are in docs/.
Design philosophy
- The assignment mechanism is primary, not the statistical model.
- API in scikit-learn style: parameters in
__init__, data infit(), learned attributes end with_. Assignmentis the contract between designs and estimators — estimators receiveAssignmentobjects, not loose DataFrames.- Randomization-based inference is the default; classical t-tests are not.
- Finite-population vs. superpopulation inference are distinguished explicitly.
- Fail fast with clear messages when designs and estimators are incompatible.
- No side effects:
fit()andrandomize()never mutate input DataFrames.
Project status
| Phase | Module | Status |
|---|---|---|
| 0 | Scaffold, exceptions, CI | ✓ Complete |
| 1 | Core (Assignment, Results, base classes) |
✓ Complete |
| 2 | Designs (CRD, BlockedCRD, ReRandomizedCRD, FactorialDesign, balance, power) | ✓ Complete |
| 3 | Estimators (DIM, BlockedDIM, Factorial, Lin, CUPED) | ✓ Complete |
| 4 | Inference (RandomizationTest, MultipleTestingCorrection, NeymanCI, BootstrapCI) | ✓ Complete (4.1–4.4; sequential → v2) |
| 5 | Diagnostics (SRMTest, AATest, BalanceReport) | ✓ Complete |
| 6 | Pipeline (ExperimentPipeline, ExperimentComparison) | ✓ Complete |
| 7 | Visualization and reporting (plots, ExperimentReport) | ✓ Complete |
Test coverage: 720 tests, all passing on CI.
See ROADMAP.md for deferred features and v2 plans, and CHANGELOG.md for the
full history of changes.
What's implemented
Designs (skxperiments.design)
CRD— Completely randomized design.BlockedCRD— Independent randomization within blocks.ReRandomizedCRD— Mahalanobis acceptance criterion with cached covariance matrix; loop withmax_attempts.FactorialDesign— 2^K factorial design with equal cell sizes; little-endian cell encoding.check_balance(assignment, covariates)— Standardized mean differences (SMD), pooled std withddof=1.power_analysis(...)— Sample size, MDE, or power for two-sample mean comparisons.
Estimators (skxperiments.estimators)
DifferenceInMeans— Simple ATE forCRDAssignment.BlockedDifferenceInMeans— Size-weighted ATE forBlockedAssignment.FactorialEstimator— All 2^K − 1 effects (main effects and interactions of all orders) forFactorialAssignment. ReturnsResultsin multi-effect mode.LinEstimator— Covariate-adjusted ATE via OLS with treatment-covariate interaction (Lin 2013).CUPED— Variance reduction with a pre-experiment covariate (Deng et al. 2013).
All estimators return Results with point estimates only; standard errors and confidence
intervals come from inference classes in skxperiments.inference.
Inference (skxperiments.inference)
RandomizationTest— Fisher's sharp null hypothesis test via Monte Carlo permutations. UsesAssignment.draw()to respect the original randomization mechanism (including rerandomization Mahalanobis criterion and within-block proportions). P-value via the Phipson & Smyth (2010) continuity correction. Three alternatives:"two-sided","greater","less". Works withDifferenceInMeans,BlockedDifferenceInMeans,LinEstimator, andCUPED.MultipleTestingCorrection— Bonferroni, Holm (FWER) and Benjamini-Hochberg (FDR) correction over a family of p-values. Accepts a multi-effectResults(typical fromFactorialEstimatorafter inference) or a list of scalarResults(for comparing independent experiments). Clips corrected p-values to[0, 1]; preserves originals inResults.extra["original_p_values"]. Default method is Holm.NeymanCI— Neyman variance-based two-sided Wald confidence interval and p-value for finite-population inference. Conservative variance forCRDAssignment(including rerandomized) and stratified variance forBlockedAssignment, consistent with the size-weighted ATE ofBlockedDifferenceInMeans. WrapsDifferenceInMeansorBlockedDifferenceInMeans; rejects superpopulation mode (useBootstrapCI).BootstrapCI— Bootstrap confidence interval (percentile or BCa) for superpopulation inference. Resamples units within each arm (within each block-by-arm stratum for blocked designs) and refits the estimator, so it works with any scalar estimator (DifferenceInMeans,BlockedDifferenceInMeans,LinEstimator,CUPED).
Diagnostics (skxperiments.diagnostics)
SRMTest— Sample Ratio Mismatch via chi-squared: observed vs. intended arm/cell allocation, flagged below a threshold (default 0.001). Two-arm and factorial.BalanceReport— Standardized mean differences (SMD) per covariate, flagging|SMD| > 0.1. Consumescheck_balance;to_dataframe()feeds the Phase 7 Love plot.AATest— A/A calibration: re-randomizes a design on fixed data, runs a wrapped inference, and checks the false-positive rate (exact binomial test) and p-value uniformity (KS).
Each returns a dedicated result with to_diagnostics_report() for pipeline aggregation.
Pipeline (skxperiments.pipeline)
ExperimentPipeline— Composes an inference (with its estimator) and diagnostics, runs them on anAssignment, and bundles the result. RunsSRMTestautomatically; diagnostics are best-effort and flags are surfaced without halting (opt-inraise_on_flag).ExperimentComparison— Compares independent experiments, applyingMultipleTestingCorrectionacross the family. Returns a comparison table ready for the forest plot. Subgroup comparison is deferred to v2.
Reporting (skxperiments.reporting)
Requires the optional viz extra (pip install skxperiments[viz]).
- Plots — diagnostic (
plot_balance,plot_srm,plot_null_distribution) and result (plot_effect,plot_forest,plot_interaction,plot_power_curve). Each returns a matplotlibAxesand accepts an optionalax. ExperimentReport— Renders aPipelineResultas a self-contained static HTML page (results table, diagnostics, embedded plots).include_plots=Falseskips the optional dependency.
What's next (v2)
The v1 feature set is complete. Deferred items live in ROADMAP.md:
SequentialTest (mSPRT/always-valid), Benjamini-Yekutieli correction, covariate-adjusted
variance in NeymanCI, studentized and block-resampling bootstrap, subgroup comparison,
a plotly backend, and interactive dashboards.
Contributing
Contributions are welcome. Please open an issue to discuss substantial changes before submitting
a pull request. The architecture has documented design decisions that should be respected — see
ROADMAP.md, the project notes in CHANGELOG.md, and the docstrings of base
classes (BaseAssignment, BaseEstimator, Results) for the contracts new code must follow.
Run the test suite with:
pytest tests/ -v
Skip slow statistical tests:
pytest tests/ -v -m "not slow"
License
MIT.
References
The implementations follow standard textbook formulations:
- Imbens, G. W., & Rubin, D. B. (2015). Causal inference for statistics, social, and biomedical sciences: An introduction. Cambridge University Press.
- Lin, W. (2013). Agnostic notes on regression adjustments to experimental data: Reexamining Freedman's critique. Annals of Applied Statistics, 7(1), 295–318.
- Morgan, K. L., & Rubin, D. B. (2012). Rerandomization to improve covariate balance in experiments. Annals of Statistics, 40(2), 1263–1282.
- Deng, A., Xu, Y., Kohavi, R., & Walker, T. (2013). Improving the sensitivity of online controlled experiments by utilizing pre-experiment data. WSDM 2013.
- Box, G. E. P., Hunter, J. S., & Hunter, W. G. (2005). Statistics for experimenters: Design, innovation, and discovery (2nd ed.). Wiley.
- Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Routledge.
- Austin, P. C. (2009). Balance diagnostics for comparing the distribution of baseline covariates between treatment groups in propensity-score matched samples. Statistics in Medicine.
- Phipson, B., & Smyth, G. K. (2010). Permutation P-values should never be zero: calculating exact P-values when permutations are randomly drawn. Statistical Applications in Genetics and Molecular Biology, 9(1).
- Fisher, R. A. (1935). The Design of Experiments. Oliver and Boyd.
- Holm, S. (1979). A simple sequentially rejective multiple test procedure. Scandinavian Journal of Statistics, 6(2), 65–70.
- Benjamini, Y., & Hochberg, Y. (1995). Controlling the false discovery rate: a practical and powerful approach to multiple testing. Journal of the Royal Statistical Society: Series B, 57(1), 289–300.
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 skxperiments-0.1.0.dev0.tar.gz.
File metadata
- Download URL: skxperiments-0.1.0.dev0.tar.gz
- Upload date:
- Size: 162.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
acfc297ef6301fc7ac07de224d67183d7bca999f94f6710c56b4ada73535987e
|
|
| MD5 |
383e7eaa421ee2693ff95cbe37a10a0f
|
|
| BLAKE2b-256 |
783c51146426e98dd71d6d96877c477c076e3b9deb77451e7f5ec70f0033b448
|
File details
Details for the file skxperiments-0.1.0.dev0-py3-none-any.whl.
File metadata
- Download URL: skxperiments-0.1.0.dev0-py3-none-any.whl
- Upload date:
- Size: 92.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3b41eaa870d4a9f9bc2e13f49ef7555af63ba086658869f47de2afb8356377ca
|
|
| MD5 |
d5a8749b34f57887b33977268f5062a0
|
|
| BLAKE2b-256 |
96f441c8d6fd6abc0fad4a68d92ba42e1f3db0fef1ab3e169eba61806cd0f629
|