Skip to content

Transfer-Function ITS: Graded Interventions with Saturation & Adstock Transforms#548

Open
drbenvincent wants to merge 56 commits intomainfrom
tf-its
Open

Transfer-Function ITS: Graded Interventions with Saturation & Adstock Transforms#548
drbenvincent wants to merge 56 commits intomainfrom
tf-its

Conversation

@drbenvincent
Copy link
Copy Markdown
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.

One reason why it's exciting is that it starts to create a bridge between CausalPy and pymc-marketing.

🎯 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

  • Estimation: OLS + Bayesian.
  • 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:

  • Modular transform system with dataclasses (Saturation, Adstock, Lag, Treatment). Very open to discussing if this is the best way forward or not.
  • Clean separation between transform specification and application logic

Dependencies: Adds pymc-marketing>=0.7.0
Breaking Changes: None
Future Work: Multiple intervention channels (this may be close to working, but just not worked through an example). Add another notebook directly focussing on a marketing-based case study.


📚 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
Copy Markdown

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB



@dataclass
class Saturation:
Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown

codecov bot commented Nov 4, 2025

Codecov Report

❌ Patch coverage is 92.45983% with 183 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.08%. Comparing base (7418939) to head (97c1f25).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
causalpy/experiments/graded_intervention_its.py 85.71% 48 Missing and 41 partials ⚠️
causalpy/pymc_models.py 70.96% 38 Missing and 25 partials ⚠️
causalpy/transform_optimization.py 90.72% 6 Missing and 8 partials ⚠️
causalpy/transforms.py 87.50% 6 Missing and 5 partials ⚠️
causalpy/skl_models.py 95.23% 1 Missing and 2 partials ⚠️
causalpy/tests/test_transfer_function_its.py 99.61% 0 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #548      +/-   ##
==========================================
- Coverage   94.59%   94.08%   -0.52%     
==========================================
  Files          45       51       +6     
  Lines        7590    10028    +2438     
  Branches      462      682     +220     
==========================================
+ Hits         7180     9435    +2255     
- Misses        249      348      +99     
- Partials      161      245      +84     

☔ 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.
Renamed 'tfits_single_channel.ipynb' to 'graded_intervention_time_series_single_channel_ols.ipynb' and updated the notebook title and references in both the notebook and the index.md file to reflect the new name and description.
Added a citation for pymc-marketing to references.bib and updated the graded intervention time series notebook to explain the use of transformation functions from pymc-marketing for modeling temporal and intensity dynamics.
Clarified the rationale for HAC standard errors, improved the explanation of autocorrelation and heteroskedasticity, and streamlined the discussion of advantages and tradeoffs. Updated ARIMAX section reference for consistency.
@juanitorduz
Copy link
Copy Markdown
Collaborator

I will take a look into this in the next days 🙏

@review-notebook-app
Copy link
Copy Markdown

review-notebook-app bot commented Nov 12, 2025

View / edit / reply to this conversation on ReviewNB

juanitorduz commented on 2025-11-12T17:48:06Z
----------------------------------------------------------------

After this cell explain you are going to generate data (and ideally hide this cell using hide-input cell tag)


@review-notebook-app
Copy link
Copy Markdown

review-notebook-app bot commented Nov 12, 2025

View / edit / reply to this conversation on ReviewNB

juanitorduz commented on 2025-11-12T17:48:06Z
----------------------------------------------------------------

Question: Can't we set priors and learn these parameters, adding them to the Bayesian model? ok! this is below :D


@review-notebook-app
Copy link
Copy Markdown

review-notebook-app bot commented Nov 12, 2025

View / edit / reply to this conversation on ReviewNB

juanitorduz commented on 2025-11-12T17:48:07Z
----------------------------------------------------------------

Shall we add HDI uncertainty in predictions ?


@review-notebook-app
Copy link
Copy Markdown

review-notebook-app bot commented Nov 12, 2025

View / edit / reply to this conversation on ReviewNB

juanitorduz commented on 2025-11-12T17:48:08Z
----------------------------------------------------------------

Nice plot! (I suggest hidding the code)


@review-notebook-app
Copy link
Copy Markdown

review-notebook-app bot commented Nov 12, 2025

View / edit / reply to this conversation on ReviewNB

juanitorduz commented on 2025-11-12T17:48:08Z
----------------------------------------------------------------

Came comment on uncertainty


@review-notebook-app
Copy link
Copy Markdown

review-notebook-app bot commented Nov 12, 2025

View / edit / reply to this conversation on ReviewNB

juanitorduz commented on 2025-11-12T17:48:09Z
----------------------------------------------------------------

Can we put the legend out? and bring the intervals (e.g. [-84, -55]) close to the figure?


@review-notebook-app
Copy link
Copy Markdown

review-notebook-app bot commented Nov 12, 2025

View / edit / reply to this conversation on ReviewNB

juanitorduz commented on 2025-11-12T17:48:10Z
----------------------------------------------------------------

It seems we have some divergences


Copy link
Copy Markdown
Collaborator

@juanitorduz juanitorduz left a comment

Choose a reason for hiding this comment

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

This is an amazing PR! I had no idea about this literature. I left some initial comments around code style. In a next round I could go deeper into the logic 💪

Really cool stuff !

# Fit OLS with HAC standard errors
if hac_maxlags is None:
n = len(y)
hac_maxlags = int(np.floor(4 * (n / 100) ** (2 / 9)))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

where does this come from? any reference?


import numpy as np
import pandas as pd
import statsmodels.api as sm
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I suggest we use https://github.com/py-econometrics/pyfixest :) It is way faster, and has all these HAC cov metrics.

from typing import Optional, Tuple

import numpy as np
import statsmodels.api as sm
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Resolve merge conflicts between tf-its branch and main:
- Keep both main's and PR's additions in __init__.py, pyproject.toml,
  references.bib, notebooks/index.md
- Combine pymc_models.py: main's BayesianBasisExpansionTimeSeries and
  StateSpaceTimeSeries + PR's TransferFunction classes
- Accept main's deletion of interrogate_badge.svg
- Use main's pymc-marketing>=0.13.1 version constraint
- Modernize type annotations (Optional/Dict -> X | None/dict)
- Fix ruff lint issues (C408, B905, SIM105, UP)
- Fix mypy errors: add None guards, proper type annotations,
  use ConvMode enum, fix variable shadowing, np.asarray wrapping

Made-with: Cursor
@read-the-docs-community
Copy link
Copy Markdown

read-the-docs-community bot commented Feb 25, 2026

Documentation build overview

📚 causalpy | 🛠️ Build #31562299 | 📁 Comparing 97c1f25 against latest (34aa8ef)


🔍 Preview build

Show files changed (160 files in total): 📝 47 modified | ➕ 113 added | ➖ 0 deleted
File Status
404.html 📝 modified
genindex.html 📝 modified
py-modindex.html 📝 modified
_modules/index.html 📝 modified
knowledgebase/design_notation.html 📝 modified
knowledgebase/estimands.html 📝 modified
knowledgebase/glossary.html 📝 modified
knowledgebase/quasi_dags.html 📝 modified
knowledgebase/structural_causal_models.html 📝 modified
notebooks/did_pymc_banks.html 📝 modified
notebooks/graded_intervention_time_series_single_channel_ols.html ➕ added
notebooks/index.html 📝 modified
notebooks/inv_prop_latent.html 📝 modified
notebooks/inv_prop_pymc.html 📝 modified
notebooks/its_pymc_comparative.html 📝 modified
notebooks/iv_pymc.html 📝 modified
notebooks/iv_weak_instruments.html 📝 modified
notebooks/sc_pymc.html 📝 modified
notebooks/sc_pymc_brexit.html 📝 modified
notebooks/staggered_did_pymc.html 📝 modified
_modules/causalpy/pymc_models.html 📝 modified
_modules/causalpy/skl_models.html 📝 modified
api/generated/causalpy.experiments.base.BaseExperiment.get_plot_data_bayesian.html 📝 modified
api/generated/causalpy.experiments.base.BaseExperiment.get_plot_data_ols.html 📝 modified
api/generated/causalpy.experiments.base.BaseExperiment.html 📝 modified
api/generated/causalpy.experiments.diff_in_diff.DifferenceInDifferences.get_plot_data_bayesian.html 📝 modified
api/generated/causalpy.experiments.diff_in_diff.DifferenceInDifferences.get_plot_data_ols.html 📝 modified
api/generated/causalpy.experiments.diff_in_diff.DifferenceInDifferences.html 📝 modified
api/generated/causalpy.experiments.graded_intervention_its.GradedInterventionTimeSeries.init.html ➕ added
api/generated/causalpy.experiments.graded_intervention_its.GradedInterventionTimeSeries.effect.html ➕ added
api/generated/causalpy.experiments.graded_intervention_its.GradedInterventionTimeSeries.effect_summary.html ➕ added
api/generated/causalpy.experiments.graded_intervention_its.GradedInterventionTimeSeries.fit.html ➕ added
api/generated/causalpy.experiments.graded_intervention_its.GradedInterventionTimeSeries.get_plot_data.html ➕ added
api/generated/causalpy.experiments.graded_intervention_its.GradedInterventionTimeSeries.get_plot_data_bayesian.html ➕ added
api/generated/causalpy.experiments.graded_intervention_its.GradedInterventionTimeSeries.get_plot_data_ols.html ➕ added
api/generated/causalpy.experiments.graded_intervention_its.GradedInterventionTimeSeries.html ➕ added
api/generated/causalpy.experiments.graded_intervention_its.GradedInterventionTimeSeries.plot.html ➕ added
api/generated/causalpy.experiments.graded_intervention_its.GradedInterventionTimeSeries.plot_diagnostics.html ➕ added
api/generated/causalpy.experiments.graded_intervention_its.GradedInterventionTimeSeries.plot_effect.html ➕ added
api/generated/causalpy.experiments.graded_intervention_its.GradedInterventionTimeSeries.plot_irf.html ➕ added
api/generated/causalpy.experiments.graded_intervention_its.GradedInterventionTimeSeries.plot_transforms.html ➕ added
api/generated/causalpy.experiments.graded_intervention_its.GradedInterventionTimeSeries.print_coefficients.html ➕ added
api/generated/causalpy.experiments.graded_intervention_its.GradedInterventionTimeSeries.summary.html ➕ added
api/generated/causalpy.experiments.graded_intervention_its.html ➕ added
api/generated/causalpy.experiments.html 📝 modified
api/generated/causalpy.experiments.instrumental_variable.InstrumentalVariable.get_plot_data_bayesian.html 📝 modified
api/generated/causalpy.experiments.instrumental_variable.InstrumentalVariable.get_plot_data_ols.html 📝 modified
api/generated/causalpy.experiments.instrumental_variable.InstrumentalVariable.html 📝 modified
api/generated/causalpy.experiments.inverse_propensity_weighting.InversePropensityWeighting.get_plot_data_bayesian.html 📝 modified
api/generated/causalpy.experiments.inverse_propensity_weighting.InversePropensityWeighting.get_plot_data_ols.html 📝 modified
api/generated/causalpy.experiments.inverse_propensity_weighting.InversePropensityWeighting.html 📝 modified
api/generated/causalpy.experiments.prepostnegd.PrePostNEGD.get_plot_data_bayesian.html 📝 modified
api/generated/causalpy.experiments.prepostnegd.PrePostNEGD.get_plot_data_ols.html 📝 modified
api/generated/causalpy.experiments.prepostnegd.PrePostNEGD.html 📝 modified
api/generated/causalpy.experiments.regression_discontinuity.RegressionDiscontinuity.get_plot_data_bayesian.html 📝 modified
api/generated/causalpy.experiments.regression_discontinuity.RegressionDiscontinuity.get_plot_data_ols.html 📝 modified
api/generated/causalpy.experiments.regression_discontinuity.RegressionDiscontinuity.html 📝 modified
api/generated/causalpy.experiments.regression_kink.RegressionKink.get_plot_data_bayesian.html 📝 modified
api/generated/causalpy.experiments.regression_kink.RegressionKink.get_plot_data_ols.html 📝 modified
api/generated/causalpy.experiments.regression_kink.RegressionKink.html 📝 modified
api/generated/causalpy.pymc_models.BayesianBasisExpansionTimeSeries.html 📝 modified
api/generated/causalpy.pymc_models.TransferFunctionARRegression.init.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.add_coord.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.add_coords.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.add_named_variable.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.build_model.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.calculate_cumulative_impact.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.calculate_impact.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.check_start_vals.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.compile_d2logp.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.compile_dlogp.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.compile_fn.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.compile_logp.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.copy.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.create_value_var.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.d2logp.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.debug.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.dlogp.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.eval_rv_shapes.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.fit.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.get_context.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.initial_point.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.logp.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.logp_dlogp_function.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.make_obs_var.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.name_for.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.name_of.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.point_logps.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.predict.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.print_coefficients.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.priors_from_data.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.profile.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.register_data_var.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.register_rv.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.replace_rvs_by_values.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.score.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.set_data.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.set_dim.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.set_initval.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.shape_from_dims.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionARRegression.to_graphviz.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.init.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.add_coord.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.add_coords.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.add_named_variable.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.build_model.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.calculate_cumulative_impact.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.calculate_impact.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.check_start_vals.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.compile_d2logp.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.compile_dlogp.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.compile_fn.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.compile_logp.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.copy.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.create_value_var.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.d2logp.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.debug.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.dlogp.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.eval_rv_shapes.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.fit.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.get_context.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.initial_point.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.logp.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.logp_dlogp_function.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.make_obs_var.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.name_for.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.name_of.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.point_logps.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.predict.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.print_coefficients.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.priors_from_data.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.profile.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.register_data_var.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.register_rv.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.replace_rvs_by_values.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.score.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.set_data.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.set_dim.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.set_initval.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.shape_from_dims.html ➕ added
api/generated/causalpy.pymc_models.TransferFunctionLinearRegression.to_graphviz.html ➕ added
api/generated/causalpy.pymc_models.html 📝 modified
api/generated/causalpy.skl_models.TransferFunctionOLS.init.html ➕ added
api/generated/causalpy.skl_models.TransferFunctionOLS.calculate_cumulative_impact.html ➕ added
api/generated/causalpy.skl_models.TransferFunctionOLS.calculate_impact.html ➕ added
api/generated/causalpy.skl_models.TransferFunctionOLS.fit.html ➕ added
api/generated/causalpy.skl_models.TransferFunctionOLS.get_coeffs.html ➕ added
api/generated/causalpy.skl_models.TransferFunctionOLS.get_metadata_routing.html ➕ added
api/generated/causalpy.skl_models.TransferFunctionOLS.get_params.html ➕ added
api/generated/causalpy.skl_models.TransferFunctionOLS.html ➕ added
api/generated/causalpy.skl_models.TransferFunctionOLS.predict.html ➕ added
api/generated/causalpy.skl_models.TransferFunctionOLS.print_coefficients.html ➕ added
api/generated/causalpy.skl_models.TransferFunctionOLS.score.html ➕ added
api/generated/causalpy.skl_models.TransferFunctionOLS.set_params.html ➕ added
api/generated/causalpy.skl_models.TransferFunctionOLS.set_score_request.html ➕ added
api/generated/causalpy.skl_models.html 📝 modified
_modules/causalpy/experiments/base.html 📝 modified
_modules/causalpy/experiments/graded_intervention_its.html ➕ added

GradedInterventionTimeSeries now implements the required effect_summary
abstract method with a NotImplementedError, directing users to the
.effect() method for counterfactual effect estimation.

Made-with: Cursor
@drbenvincent
Copy link
Copy Markdown
Collaborator Author

Branch sync and fixes to bring PR to green

This PR was 222 commits behind main and had merge conflicts. Here's what was done to bring it current:

Merge conflict resolution (7 files)

  • causalpy/__init__.py: Kept both main's additions (StaggeredDiD, extract_lift_for_mmm, variable_selection_priors) and PR's (GradedInterventionTimeSeries, transforms)
  • causalpy/pymc_models.py: Combined main's new classes (BayesianBasisExpansionTimeSeries, StateSpaceTimeSeries) with PR's TransferFunction classes
  • pyproject.toml: Adopted main's pymc-marketing>=0.13.1 version constraint
  • docs/source/references.bib: Merged bibliography entries from both branches
  • docs/source/notebooks/index.md: Kept both Graded ITS and Comparative ITS notebook sections
  • causalpy/tests/test_integration_pymc_examples.py: Removed stale try/except superseded by main's contextlib.suppress
  • docs/source/_static/interrogate_badge.svg: Accepted main's deletion

Lint and type fixes

  • Modernized type annotations: Optional[X]X | None, Dictdict (ruff UP rules)
  • Fixed ruff issues: dict() → dict literals (C408), zip() without strict= (B905), try/except/passcontextlib.suppress (SIM105)
  • Fixed ~50 mypy errors across PR files: added None guards for idata access, np.asarray() wrapping for pandas .values calls, proper base-class type declarations for transform variables, ConvMode enum usage
  • Updated copyright header to 2026

ABC compliance

  • Added effect_summary() stub to GradedInterventionTimeSeries to satisfy the BaseExperiment abstract method contract introduced on main after this PR was created. Raises NotImplementedError directing users to .effect() for now.

All checks now pass: tests (3.11, 3.14), pre-commit.ci, docs build, packaging.

- Add missing type hints for saturation, adstock, lag params in
  _fit_ols_with_transforms
- Use Literal["hac", "arimax"] for error_model params instead of str
- Replace Optional[Any] with Any | None in docstrings
- Replace Dict[str, Prior] with dict[str, Prior] in docstrings
- Add type annotations to treatment_names and n_treatments attributes
- Add parameter type hints to priors_from_data (X, y) in TF classes
- Add full type hints to build_model in both TF classes

Made-with: Cursor
drbenvincent added a commit that referenced this pull request Feb 25, 2026
Document the convention (from PR #548 review feedback) to use modern
Python 3.10+ type hint syntax: X | None, lowercase builtins, Literal.

Made-with: Cursor
Addresses review feedback from @juanitorduz on PR #548: the
saturation_type → SaturationTransform if/elif/else block was duplicated
3 times in transform_optimization.py. Replaced with a single
create_saturation() factory function in transforms.py backed by a
SATURATION_TYPES registry dict.

Made-with: Cursor
drbenvincent added a commit that referenced this pull request Feb 28, 2026
Document the convention (from PR #548 review feedback) to use modern
Python 3.10+ type hint syntax: X | None, lowercase builtins, Literal.

Made-with: Cursor
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