Skip to content

tmaringgele/CausalBoundingEngine

Repository files navigation

CausalBoundingEngine

CBE Logo

A unified Python framework for causal effect bounding algorithms

PyPI version Python 3.12+ Documentation License: MIT GitHub

Documentation | Quick Start | Examples | Contributing

Overview

CausalBoundingEngine is a modular Python package that provides a unified interface for comparing and applying state-of-the-art causal bounding algorithms. It enables researchers and practitioners to compute bounds on causal effects when unmeasured confounding is present.

Key Features

🔧 Unified Interface - Consistent API across all algorithms and scenarios
📊 Multiple Algorithms - Manski, Tian-Pearl, Autobound, Causaloptim, Zaffalonbounds, and more
🎯 Flexible Scenarios - Support for confounded and instrumental variable settings
🔗 External Engines - Integration with R (rpy2) and Java (jpype1) backends
🚀 Easy Extension - Simple framework for adding new algorithms and scenarios
📚 Comprehensive Docs - Detailed documentation with examples and API reference

Supported Algorithms

Algorithm ATE PNS Scenarios Dependencies Reference
Manski BinaryConf Core Manski (1990)
Tian-Pearl BinaryConf Core Tian & Pearl (2000)
Autobound BinaryConf, BinaryIV Core Duarte et al. (2023)
Entropybounds BinaryConf Core Jiang et al. (2023)
Causaloptim BinaryConf, BinaryIV R Sachs et al. (2022)
Zaffalonbounds BinaryConf, BinaryIV Java Zaffalon et al. (2022)
ZhangBareinboim ContIV Core Zhang & Bareinboim (2021)

Installation

🐍 For smooth sailing, Python 3.12 or greater is recommended.
While CausalBoundingEngine supports Python 3.8+, you may encounter issues in some specific situations with older versions.

Core Package

pip install causalboundingengine

Optional Dependencies

For extended functionality, install with optional dependencies:

# R integration (Causaloptim algorithm)
pip install causalboundingengine[r]

# Java integration (Zaffalonbounds algorithm)  
pip install causalboundingengine[java]

# All optional features
pip install causalboundingengine[full]

# Documentation building
pip install causalboundingengine[docs]

System Dependencies

For algorithms requiring external engines:

R Support (for Causaloptim):

# Ubuntu/Debian
sudo apt install r-base

# macOS
brew install r

# Windows: Download from https://cran.r-project.org/

Java Support (for Zaffalonbounds):

# Ubuntu/Debian
sudo apt install default-jre

# macOS  
brew install openjdk

# Windows: Download from https://adoptium.net/

Quick Start

Note: numeric results in the examples are for illustrative porpuses and not necessarily correct.

Basic Usage

import numpy as np
from causalboundingengine.scenarios import BinaryConf

# Your observational data
X = np.array([0, 1, 1, 0, 1, 0, 1, 0])  # Treatment
Y = np.array([1, 0, 1, 0, 1, 1, 0, 1])  # Outcome

# Create scenario and compute bounds
scenario = BinaryConf(X, Y)

# Compute ATE bounds with different algorithms
manski_bounds = scenario.ATE.manski()           # (-1.0, 1.0) - Most conservative
autobound_bounds = scenario.ATE.autobound()     # (-0.5, 0.5) - LP optimization

print(f"Manski bounds:    {manski_bounds}")
print(f"Autobound bounds:  {autobound_bounds}")

Instrumental Variable Analysis

from causalboundingengine.scenarios import BinaryIV

# IV data (e.g., randomized trial with non-compliance)
Z = np.array([0, 1, 1, 0, 1, 0, 1, 0])  # Instrument (randomization)
X = np.array([0, 1, 0, 0, 1, 0, 1, 0])  # Treatment (actual uptake)  
Y = np.array([1, 0, 1, 0, 1, 1, 0, 1])  # Outcome

# Create IV scenario
scenario = BinaryIV(X, Y, Z)

# Compute bounds leveraging IV assumptions
iv_bounds = scenario.ATE.autobound()
print(f"IV-based bounds: {iv_bounds}")  # Often tighter than confounded case

Continuous Outcomes

from causalboundingengine.scenarios import ContIV

# Binary instrument/treatment with continuous outcome
Z = np.array([0, 1, 1, 0, 1])           # Binary instrument
X = np.array([0, 1, 1, 0, 1])           # Binary treatment  
Y = np.array([0.2, 0.8, 0.6, 0.1, 0.9]) # Continuous outcome [0,1]

scenario = ContIV(X, Y, Z)
bounds = scenario.ATE.zhangbareinboim()
print(f"Continuous outcome bounds: {bounds}")

Examples

Algorithm Comparison

import numpy as np
from causalboundingengine.scenarios import BinaryConf

# Generate example data
np.random.seed(42)
n = 1000
X = np.random.binomial(1, 0.3, n)
Y = np.random.binomial(1, 0.6, n)

scenario = BinaryConf(X, Y)

# Compare multiple algorithms
algorithms = ['manski', 'autobound', 'entropybounds']
results = {}

for alg in algorithms:
    if alg == 'entropybounds':
        bounds = getattr(scenario.ATE, alg)(theta=0.5)
    else:
        bounds = getattr(scenario.ATE, alg)()
    results[alg] = bounds
    print(f"{alg:15} ATE bounds: {bounds}")

# Output:
# manski          ATE bounds: (-0.7, 0.7)
# autobound       ATE bounds: (-0.3, 0.3)
# entropybounds   ATE bounds: (-0.2, 0.2)

Sensitivity Analysis

# Sensitivity analysis with Entropybounds
thetas = [0.1, 0.3, 0.6, 0.8]
for theta in thetas:
    bounds = scenario.ATE.entropybounds(theta=theta)
    width = bounds[1] - bounds[0]
    print(f"θ={theta}: bounds={bounds}, width={width:.3f}")

# Output shows how bounds widen as assumptions weaken:
# θ=0.1: bounds=(-0.15, 0.15), width=0.735
# θ=0.3: bounds=(-0.25, 0.25), width=0.995  
# θ=0.6: bounds=(-0.35, 0.35), width=1.000
# θ=0.8: bounds=(-0.45, 0.45), width=1.000

Robust Analysis Workflow

def robust_analysis(X, Y, Z=None):
    """Run multiple algorithms for robustness."""
    if Z is None:
        scenario = BinaryConf(X, Y)
        algorithms = ['manski', 'autobound']
    else:
        scenario = BinaryIV(X, Y, Z)  
        algorithms = ['autobound']  # Add 'causaloptim', 'zaffalonbounds' if available
    
    results = {}
    for alg in algorithms:
        try:
            results[alg] = getattr(scenario.ATE, alg)()
            print(f"✓ {alg}: {results[alg]}")
        except Exception as e:
            print(f"✗ {alg}: {e}")
    
    return results

# Run robust analysis
bounds_dict = robust_analysis(X, Y)

Scenarios

CausalBoundingEngine organizes algorithms by causal scenario:

BinaryConf

  • Use case: Observational studies with binary treatment/outcome
  • Assumptions: Potential unmeasured confounding
  • Algorithms: Manski, Autobound, Entropybounds, Causaloptim, Zaffalonbounds

BinaryIV

  • Use case: Instrumental variable analysis with binary variables
  • Assumptions: Valid instrument (relevance, exclusion, exogeneity)
  • Algorithms: Autobound, Causaloptim, Zaffalonbounds

ContIV

  • Use case: Binary instrument/treatment with continuous outcome [0,1]
  • Assumptions: Valid instrument, bounded outcome
  • Algorithms: ZhangBareinboim

Advanced Features

Custom Algorithm Parameters

# Entropybounds with custom confounding strength
bounds = scenario.ATE.entropybounds(theta=0.2)

# Causaloptim with custom R path
bounds = scenario.ATE.causaloptim(r_path="/usr/local/bin/R")

Algorithm Availability

# Check available algorithms
print("ATE algorithms:", scenario.get_algorithms('ATE'))
print("PNS algorithms:", scenario.get_algorithms('PNS'))

# Dynamic algorithm access
algorithm_name = 'manski'
if algorithm_name in scenario.get_algorithms('ATE'):
    bounds = getattr(scenario.ATE, algorithm_name)()

Error Handling

import logging
logging.basicConfig(level=logging.WARNING)

# Algorithms return trivial bounds on failure
bounds = scenario.ATE.some_algorithm()
if bounds == (-1.0, 1.0):  # ATE trivial bounds
    print("Algorithm failed, returned trivial bounds")

Documentation

📖 Full Documentation: https://causalboundingengine.readthedocs.io/

The documentation includes:

Testing

CausalBoundingEngine includes a comprehensive test suite to ensure reliability.

Quick Test Run

# Run basic tests (minimal dependencies)
python -m pytest tests/test_dummy.py tests/test_scenarios.py::TestDataClass -v

# Run core algorithm tests  
python -m pytest tests/test_core_algorithms.py -v

# Run all tests
python -m pytest tests/ -v

Test Coverage

Core functionality - Data structures, basic algorithms
Algorithm interfaces - Manski, Tian-Pearl bounds
Scenario framework - Data handling, dispatching
Integration tests - End-to-end workflows
⚠️ Optional components - Require additional dependencies

See TESTING.md for detailed testing documentation.

Contributing

We welcome contributions! The process is simple:

  1. Fork the repository on GitHub
  2. Clone your fork and install: pip install -e .
  3. Make your changes and add tests
  4. Submit a Pull Request

See our Contributing Guide for details.

Areas for Contribution

  • 🔧 New algorithm implementations
  • 📊 Additional causal scenarios
  • 🐛 Bug fixes and improvements
  • 📚 Documentation and examples
  • 🚀 Performance optimizations

Citation

If you use CausalBoundingEngine in your research, please cite the relevant algorithm papers. See the References section for complete citations.

BibTeX Template

@software{causalboundingengine,
  title={CausalBoundingEngine: A Unified Framework for Causal Effect Bounding},
  author={[Tobias Maringgele]},
  year={2025},
  url={https://github.com/tmaringgele/CausalBoundingEngine},
  note={Python package for causal effect bounding algorithms}
}

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

CausalBoundingEngine integrates algorithms from multiple research papers. We gratefully acknowledge:

  • Manski (1990) - Nonparametric bounds foundation
  • Tian & Pearl (2000) - Probability of causation bounds
  • Duarte et al. (2023) - Autobound optimization approach
  • Jiang et al. (2023) - Entropy-based weak confounding
  • Sachs et al. (2022) - Causaloptim R library
  • Zaffalon et al. (2022) - Causal expectation maximisation approach
  • Zhang & Bareinboim (2021) - Continuous outcome bounding

See the References page for complete citations and attributions.


Built with 💙 for causal inference

DocumentationPyPIGitHub