causal-sampler
causal-sampler provides causal resampling for reverse causal inference: estimate
an interventional distribution of observations X under an intervention on Y,
then use the generated (X, Y) pairs to train a downstream predictor.
Version 1.0.0 integrates causalbootstrapping 0.2.6 and extends the CB/CW-GMM interfaces in 0.0.5 with CW-DPMM, hybrid block Gibbs-HMC and a unified identification-guided image DDPM. Identification and interpretation depend on the supplied causal graph, measured variables, overlap and distribution estimates; generated data are an estimated interventional sample, not independently verified unconfounded observations.
Installation
The package declares Python >=3.9 and depends on
causalbootstrapping==0.2.6. Numerical dependency ranges admit compatible
NumPy 1.x/2.x versions and newer Python interpreters. Python 3.12 is a useful
starting point; see validation notes for tested versions.
Create an isolated environment:
conda create -n causal-sampler python=3.12
conda activate causal-sampler
python -m pip install --upgrade pip
Install the release wheel, using its actual path:
python -m pip install dist/causal_sampler-1.0.0-py3-none-any.whl
Or install from this source directory:
python -m pip install .
# Include notebook dependencies:
python -m pip install ".[demo]"
# Editable development installation:
python -m pip install -e ".[demo,dev]"
Once 1.0.0 is published to PyPI, it can also be installed with
python -m pip install causal-sampler==1.0.0.
Publish causalbootstrapping 0.2.6 first, then causal-sampler 1.0.0. Before the dependency is on PyPI, install its prepared wheel alongside this wheel using your actual local paths:
python -m pip install /path/to/causalbootstrapping-0.2.6-py3-none-any.whl dist/causal_sampler-1.0.0-py3-none-any.whl
The dependency is not vendored and no machine-specific path is embedded in package metadata.
PyTorch is a required dependency for the public pipeline in this release. For a CPU-only Linux environment, you may install the tested CPU build first:
python -m pip install "torch==2.8.0" --index-url https://download.pytorch.org/whl/cpu
python -m pip install .
For CUDA, install a compatible PyTorch build for your platform before the package;
then select device="cuda" for HMC/DDPM. GPU execution was not part of the local
release validation. The Python graphviz dependency is installed automatically;
rendering causal graphs additionally requires the Graphviz system executable.
Resampling without graph rendering does not require that executable.
Public samplers
from causal_sampler import pipeline as cs_pipe
# Direct imports are also supported:
from causal_sampler import CausalBootstrapSampler, CausalDDPMSampler
| Method | Public class | Main fit configuration |
|---|---|---|
| Empirical causally weighted bootstrap | CausalBootstrapSampler |
Density estimator, kernel, optional weight transformation |
| Causally weighted Gaussian mixture | CausalGMMSampler |
comp_k, covariance type, weighted EM settings |
| Causally weighted Dirichlet process mixture | CausalDPMMSampler |
alpha, prior, covariance type, Gibbs iterations |
| Hybrid block Gibbs-HMC | CausalBlockGibbsHMC |
Update blocks, burn-in, thinning, device |
| Unified ID-guided conditional image DDPM | CausalDDPMSampler |
Variable types, image shape, network and diffusion settings |
All five classes offer fit(), resample() and fit_deconf_model(). Method-specific
training arguments and return conventions are documented in their docstrings.
The DDPM additionally offers save_checkpoint(), load_checkpoint() and
from_checkpoint(). Persistence is not a shared high-level API for every sampler.
Quick start: front-door bootstrap
This small synthetic example needs no downloaded dataset. U is used only to
simulate unobserved confounding and is deliberately absent from data_dict.
import numpy as np
from causal_sampler import pipeline as cs_pipe
rng = np.random.default_rng(42)
n = 120
u = rng.normal(size=n)
y = (u + rng.normal(size=n) > 0).astype(int)
z = y + rng.normal(scale=0.7, size=n)
x = np.column_stack([
2 * z + u + rng.normal(size=n),
z - u + rng.normal(size=n),
])
training_data = {"X": x, "Y": y[:, None], "Z": z[:, None]}
graph = "Y;Z;X;Y->Z;Z->X;Y<->X;"
flow = cs_pipe.CausalBootstrapSampler(
causal_graph=graph,
cause_var_name="Y", effect_var_name="X",
intv_values=[0, 1], data_dict=training_data,
est_method="kde", bandwidth="scott",
)
flow.fit()
X_deconf, Y_deconf, source_idx = flow.resample(
n_samples=[100, 100], random_seed=42,
return_samples=True, return_indices=True, verbose=0,
)
assert np.array_equal(X_deconf, x[source_idx])
Y_deconf contains the assigned intervention values. Under some identification
formulas these differ from the original labels of the source rows. source_idx
always refers to row positions in the data supplied to this sampler; it is not a
DataFrame index label. The indices remain aligned after shuffling.
For non-DDPM samplers, supply finite numeric arrays shaped (N, d); scalar (N,)
arrays are also normalized to (N, 1). Every variable must use the same row order
and count. An integer n_samples=100 requests 100 per intervention, not 100 in
total. A sequence follows intv_values order. Generated arrays are available as
flow.deconf_X and flow.deconf_Y even with return_samples=False.
Mixture models and downstream prediction
gmm = cs_pipe.CausalGMMSampler(
causal_graph=graph, cause_var_name="Y", effect_var_name="X",
intv_values=[0, 1], data_dict=training_data, est_method="kde",
)
gmm.fit(comp_k=3, cov_type="diag", max_iter=50, random_seed=42, verbose=0)
X_gmm, Y_gmm = gmm.resample(100, random_seed=42, return_samples=True)
from sklearn.ensemble import RandomForestClassifier
classifier = gmm.fit_deconf_model(RandomForestClassifier(random_state=42))
Use CW-DPMM when the number of components is to be inferred under its prior:
dpmm = cs_pipe.CausalDPMMSampler(
causal_graph=graph, cause_var_name="Y", effect_var_name="X",
intv_values=[0, 1], data_dict=training_data, est_method="kde",
)
dpmm.fit(alpha=1.0, cov_type="diag", init_clusters=2,
burn_in=10, max_iter=30, random_seed=42, verbose=0)
X_dpmm, Y_dpmm = dpmm.resample(100, random_seed=42, return_samples=True)
max_iter counts retained DPMM sweeps after its burn_in sweeps. Generation
uses the final fitted mixture state. Repeated resample(random_seed=42) calls
on an unchanged DPMM now reset its actual per-intervention generators. Historical
sampling sequences are not guaranteed to match 0.0.5 or development snapshots.
Weight transformations
CB, CW-GMM and CW-DPMM accept the following fit options:
flow.fit(weight_transform=None) # unchanged weights
flow.fit(weight_transform="ess_norm", ess_fraction=0.1)
flow.fit(weight_transform="log") # log1p(weights)
flow.fit(weight_transform=[0.01, 0.99]) # quantile clipping
Quantiles are computed on positive weights only; structural zeros remain zero.
ESS adjustment uses a power transformation to meet the requested ESS floor while
preserving zero support. It is not only multiplication by a normalization constant.
All nontrivial transformations change the empirical target distribution and should
be reported with sensitivity analyses. log compression depends on the absolute
scale of the input weights. An ESS fraction is a tuning choice, not a guarantee
of causal validity or additional independent information.
Misspelled or unsupported options raise an error. Development-only arguments
truncate_weights and truncated_weight are not supported; use weight_transform.
For direct calls to compute_causal_weight(), the argument is named transform.
HMC and DDPM
See the sampler guide for HMC update blocks and initialization, and the complete DDPM API for every constructor, fit, generation and checkpoint option.
The DDPM accepts one image effect, one scalar categorical cause, and auxiliary
conditional mixtures certified by symbolic leaf elimination. It does not
implement every formula returned by ID. Unsupported expressions raise
UnsupportedIDExpression. variable_types and image_shape must be explicit.
Its optional reconstruction consistency penalty defaults to zero.
Run examples and notebooks
python examples/quickstart.py --method all
python -m jupyterlab Demo
- Demo 00: all sampler APIs: self-contained, small CPU examples for all five samplers, source indices, weight options and checkpoints.
- Demo 01: synthetic back-door: original classification/regression study; requires external CSVs and has refreshed interface notes.
- Demo 02: background-MNIST: preserves the original experiment; requires the external CSVs listed in its first cell. The large pretrained pickle is no longer distributed or loaded automatically.
- Demo 03: general graph: original external-CSV experiment with updated API guidance.
The short examples demonstrate executable interfaces, not tuned experimental performance. Fit samplers, density estimators and downstream models on training partitions only; split by participant where observations repeat within a subject.
Development and release
python -m unittest discover -s tests -v
python -m build
python -m twine check dist/*
See CHANGELOG.md, migration notes, and RELEASE.md. The source distribution includes documentation, notebooks, examples and tests. The wheel contains the importable package and license.
Citation and license
The original package citation entries are retained below. They provide background for causal bootstrapping and mechanism learning, not a claim that every added sampler is described in those papers.
@article{mao2024mechanism,
title={Mechanism learning: Reverse causal inference in the presence of multiple unknown confounding through front-door causal bootstrapping},
author={Mao, Jianqiao and Little, Max A},
journal={arXiv preprint arXiv:2410.20057},
year={2024}
}
@article{little2019causal,
title={Causal bootstrapping},
author={Little, Max A and Badawy, Reham},
journal={arXiv preprint arXiv:1910.09648},
year={2019}
}
Author: Jianqiao Mao. Licensed under the GNU GPL version 3 text supplied with the original release; see LICENSE.
Changes from the prepared 0.0.6 package
- Dependency pin advances to causalbootstrapping 0.2.6; package metadata no longer imposes Python <3.11. PyTorch now requires >=2.5,<3.
- The CB adapter calls the dependency's validated bootstrapper and uses its
returned source indices, then applies one shared shuffle to X, Y and indices.
sampling_mode="exact"remains an alias for"robust"at this top-level API. - Invalid computed weights raise with the intervention value in the message. NaNs are not silently replaced; fix the density/support issue before training.
- Public class names, fit/resample signatures and return conventions remain. Seeded CB samples may differ from 0.0.6; repeatability within 1.0.0 is tested.
- DDPM architecture and checkpoint format are unchanged from the prepared unified implementation. Experimental pre-unification checkpoints still require migration; supported ID-expression restrictions remain in force.
Release files for causal-sampler 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| causal_sampler-1.0.0.tar.gz | 147.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| causal_sampler-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 246.7 kB
Release files / causal_sampler-1.0.0.tar.gz
| Download URL | causal_sampler-1.0.0.tar.gz |
|---|---|
| Size | 147.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
dfff3431326e1203fa047e35d655d242f1716c22ae1f14e2b6a75a1d5c7d18de
|
|
BLAKE2b-256 checksum How to use checksums |
26f464231e52622db9f345165423a791e1384dea99262741a27ed38d313b9764
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.9.12
|
Release files / causal_sampler-1.0.0-py3-none-any.whl
| Download URL | causal_sampler-1.0.0-py3-none-any.whl |
|---|---|
| Size | 99.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8526033429044a9efe4e942fc8703b1c083aaf6ceea9f507e3c3b3edc87a9091
|
|
BLAKE2b-256 checksum How to use checksums |
e22c2e0d838843f8352d0209ac3589290b3b484c25bb2602a683af1c5bfb8d9f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.9.12
|