Skip to content

Conversation

@drbenvincent
Copy link
Collaborator

@drbenvincent drbenvincent commented Nov 3, 2025

This PR introduces Transfer-Function Interrupted Time Series (TF-ITS), a powerful new experiment class that extends CausalPy's causal inference capabilities to handle graded (non-binary) interventions in single-market time series data.

🎯 What This Adds

  • Unlike traditional ITS methods that focus on binary on/off treatments, TF-ITS enables practitioners to:
  • Model interventions with varying intensity (e.g., advertising spend, policy intensity, promotional campaigns)
  • Account for diminishing returns through saturation transforms (Hill, logistic, Michaelis-Menten)
  • Capture carryover effects using adstock transforms (geometric decay with configurable half-life)
  • Estimate window-level causal lift by constructing counterfactuals with scaled or zeroed interventions

This makes TF-ITS particularly valuable for marketing mix modeling, policy evaluation, and any scenario where treatment intensity varies over time.

🔧 Implementation Details

MVP Scope (Non-Bayesian):

  • Estimation: OLS regression with HAC standard errors (via statsmodels)
  • Transforms: Leverages pymc-marketing transform library for saturation and adstock functions
  • Counterfactuals: Flexible engine for computing treatment effects by scaling exposures in specified time windows
  • Diagnostics: Residual ACF/PACF plots and Ljung-Box tests
  • Visualization: Model fit plots and impulse response functions (IRF)

Architecture:

  • Designed for future Bayesian extension following CausalPy conventions
  • Modular transform system with dataclasses (Saturation, Adstock, Lag, Treatment)
  • Clean separation between transform specification and application logic

📦 What's Included

  • Core Implementation
    • causalpy/experiments/transfer_function_its.py: New TransferFunctionITS experiment class
    • causalpy/transforms.py: Transform dataclasses and application logic
  • Testing
    • causalpy/tests/test_transfer_function_its.py: Comprehensive unit and integration tests
  • Documentation
    • docs/source/notebooks/tfits_single_channel.ipynb: Tutorial notebook with simulated advertising example
    • Updated glossary with TF-ITS definition and key concepts
    • Citations to Box & Tiao (1975) intervention analysis literature
  • Dependencies
    • Added pymc-marketing>=0.7.0 for transform functions

🎓 Example Use Case

The tutorial notebook demonstrates estimating the causal lift of a TV advertising flight campaign by:

  1. Fitting a model with baseline controls (trend, seasonality) + transformed TV spend
  2. Applying Hill saturation (diminishing returns) and geometric adstock (3-week half-life)
  3. Computing counterfactual sales if TV spend had been zeroed during the flight window
  4. Quantifying total and mean weekly lift with proper diagnostics

🚀 Why This Matters

This addition positions CausalPy as a comprehensive toolkit for time-series causal inference, complementing existing methods:

  • RDD/IV: Cross-sectional causal inference
  • DiD/Synthetic Control: Panel data methods
  • ITS: Binary treatment time series
  • TF-ITS (NEW): Graded treatment time series with realistic dose-response modeling

The non-Bayesian MVP enables fast prototyping and production deployment, while the architecture is ready for future Bayesian implementations that will provide full uncertainty quantification and hierarchical modeling capabilities.


Dependencies: Adds pymc-marketing>=0.7.0
Breaking Changes: None
Future Work: Bayesian estimation, parameter grid search, multi-channel attribution


📚 Documentation preview 📚: https://causalpy--548.org.readthedocs.build/en/548/

@drbenvincent drbenvincent added enhancement New feature or request major labels Nov 3, 2025
@review-notebook-app
Copy link

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB



@dataclass
class Saturation:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We avoided this intentionally with pymc-marketing. Is this the only way to implement this?

Reference:
https://williambdean.github.io/blog/posts/2024/pymc-marketing-strategy-pattern/

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for flagging this. Very early days on this PR, will look into changing it

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully resolved in 659b502

Refactored transform classes to use a strategy pattern with explicit Adstock, Saturation, and Lag implementations. Added transform_optimization.py for grid search and optimization of transform parameters. Updated TransferFunctionITS to support transform parameter estimation and metadata. Revised tests to use new transform classes and parameter estimation workflows.
Expanded and clarified docstrings in transfer_function_its.py to document the nested parameter estimation approach for saturation and adstock transforms. Updated the example and usage instructions to reflect the new estimation workflow. Revised the notebook to demonstrate transform parameter estimation via grid search, show parameter recovery, and clarify the distinction between grid search and continuous optimization. Removed the outdated and redundant test class for TransferFunctionITS in test_transfer_function_its.py.
@codecov
Copy link

codecov bot commented Nov 4, 2025

Codecov Report

❌ Patch coverage is 89.96898% with 97 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.10%. Comparing base (757d150) to head (4ebd026).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
causalpy/experiments/graded_intervention_its.py 84.04% 56 Missing ⚠️
causalpy/transform_optimization.py 80.43% 27 Missing ⚠️
causalpy/transforms.py 89.15% 9 Missing ⚠️
causalpy/skl_models.py 91.80% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #548      +/-   ##
==========================================
- Coverage   95.59%   94.10%   -1.50%     
==========================================
  Files          29       33       +4     
  Lines        2681     3648     +967     
==========================================
+ Hits         2563     3433     +870     
- Misses        118      215      +97     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Expanded documentation and code comments to better explain HAC (Newey-West) standard errors, their purpose, and the hac_maxlags parameter. Added a detailed explanation and citation in the notebook, and improved docstrings and print output in transfer_function_its.py. Added the Newey-West reference to references.bib.
Expanded the TF-ITS notebook with a detailed explanation of autocorrelation in time series, its impact on causal inference, and the motivation for using HAC (Newey-West) standard errors. Updated the simulation to generate autocorrelated errors using an AR(1) process, and clarified the importance of robust inference in the context of time series interventions.
Extended TransferFunctionITS and transform optimization to support ARIMAX (ARIMA with exogenous variables) error models in addition to HAC standard errors. Updated model fitting, parameter estimation, and documentation to allow users to specify error_model ('hac' or 'arimax') and ARIMA order. Added comprehensive tests for ARIMAX functionality and updated the notebook to demonstrate ARIMAX usage and comparison with HAC.
Refactors GradedInterventionTimeSeries and TransferFunctionOLS to follow the standard CausalPy pattern: the experiment class now takes an unfitted model and handles transform parameter estimation, fitting, and result extraction. Removes the with_estimated_transforms factory method, updates all docstrings, and adapts tests and documentation to the new workflow. This enables more flexible and consistent usage for multi-treatment and advanced modeling scenarios.
Introduces new plotting methods to GradedInterventionTimeSeries, including plot_effect and plot_transforms, and renames diagnostics() to plot_diagnostics(). Updates tests to cover new plotting features. Enhances documentation and notebook explanations for model fitting and parameter estimation, and updates the interrogate badge.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request major

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants