Skip to content

Conversation

@NathanielF
Copy link
Contributor

@NathanielF NathanielF commented Nov 19, 2025

Just a draft for the minute. Working through some ideas.


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

Comment on lines 54 to 57
:param vs_prior_type : str or None, default=None
Type of variable selection prior: 'spike_and_slab', 'horseshoe', or None.
If None, uses standard normal priors.
:param vs_hyperparams : dict, optional
Copy link
Contributor

Choose a reason for hiding this comment

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

This is sphinx format and not numpy

Copy link
Collaborator

Choose a reason for hiding this comment

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

We should add that into AGENTS.md if it's not already there.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is sphinx format and not numpy

You got me. The doc strings were AI generated. Will fix.

Provides continuous shrinkage with heavy tails, allowing strong signals
to escape shrinkage while weak signals are dampened:
β_j = τ · λ̃_j · β_j^raw
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should be able to add maths in here for nice rendering in the API docs

Signed-off-by: Nathaniel <[email protected]>
@review-notebook-app
Copy link

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

Signed-off-by: Nathaniel <[email protected]>
Signed-off-by: Nathaniel <[email protected]>
Signed-off-by: Nathaniel <[email protected]>
Signed-off-by: Nathaniel <[email protected]>
@codecov
Copy link

codecov bot commented Nov 20, 2025

Codecov Report

❌ Patch coverage is 95.45455% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.32%. Comparing base (8e672f2) to head (dbc8614).

Files with missing lines Patch % Lines
causalpy/variable_selection_priors.py 89.34% 6 Missing and 7 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #568      +/-   ##
==========================================
+ Coverage   93.21%   93.32%   +0.11%     
==========================================
  Files          35       37       +2     
  Lines        5511     5785     +274     
  Branches      358      375      +17     
==========================================
+ Hits         5137     5399     +262     
- Misses        246      252       +6     
- Partials      128      134       +6     

☔ 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.

Signed-off-by: Nathaniel <[email protected]>
Signed-off-by: Nathaniel <[email protected]>
Signed-off-by: Nathaniel <[email protected]>
Signed-off-by: Nathaniel <[email protected]>
Signed-off-by: Nathaniel <[email protected]>
Signed-off-by: Nathaniel <[email protected]>
Signed-off-by: Nathaniel <[email protected]>
@NathanielF NathanielF marked this pull request as ready for review November 22, 2025 08:22
@NathanielF
Copy link
Contributor Author

Marking this one as ready for review. There is still some work to be done on the notebook illustrating the functionality. But i think there is enough here that's it worth flagging the architecture choices for discussion. I've made the variable selection priors available as a module. Currently, just integrated with the IV class, but in principle can be dropped into all regression based modules with coefficients. The pattern simply requires an if-else block to be used in e.g. the propensity score model, linear regression model etc....

What do you guys think?

Signed-off-by: Nathaniel <[email protected]>
Signed-off-by: Nathaniel <[email protected]>
Signed-off-by: Nathaniel <[email protected]>
@juanitorduz
Copy link
Collaborator

Great @NathanielF ! I think the notebooks need a bit more storyline and explanation 🙏

@NathanielF
Copy link
Contributor Author

Cool, thanks @juanitorduz . I can take another pass at it this weekend.

@drbenvincent drbenvincent added the enhancement New feature or request label Dec 5, 2025
@drbenvincent
Copy link
Collaborator

Will take a look at this. But it's worth updating from main first. There are likely to be some merge conflicts

@@ -0,0 +1,2219 @@
{
Copy link
Collaborator

@drbenvincent drbenvincent Dec 5, 2025

Choose a reason for hiding this comment

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

It could be worth adding a graphviz DAG here to represent the DGP for the simulated data.

I'd also be tempted to add a corresponding short paragraph to explain the data setup a bit.

Could add in a link to the knowledge base page you recently added


Reply via ReviewNB

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a note and clarification

@@ -0,0 +1,2219 @@
{
Copy link
Collaborator

@drbenvincent drbenvincent Dec 5, 2025

Choose a reason for hiding this comment

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

Can we add bibtex references (and citations in text) for the spike-and-slab and the horseshoe.

For the horseshoe, are the lambdas also {0,1} ?


Reply via ReviewNB

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Clarified this too. Lambdas are not in {0, 1} strictly speaking since we're using a relaxed spike and slab, the gammas aren't either. Also clarified this. Added a reference to the Kaplan book

@@ -0,0 +1,2219 @@
{
Copy link
Collaborator

@drbenvincent drbenvincent Dec 5, 2025

Choose a reason for hiding this comment

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

temperature and pi could more clearly map on to the equations given in the above spike-and-slab + horseshoe sections


Reply via ReviewNB

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Linked this a back a bit. Didn't give a full breakdown in formulas of how the hyperparameters work... this seemed overkill?

@@ -0,0 +1,2219 @@
{
Copy link
Collaborator

@drbenvincent drbenvincent Dec 5, 2025

Choose a reason for hiding this comment

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

add hide-input as the cell tag


Reply via ReviewNB

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@@ -0,0 +1,2219 @@
{
Copy link
Collaborator

@drbenvincent drbenvincent Dec 5, 2025

Choose a reason for hiding this comment

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

Can you add a bit of explanation. I'm still not over my cold, so I'm probably missing something, but my naive prediction would be that parameters would be heaped at zero. Could you just add something in there to address whatever misunderstanding I have there


Reply via ReviewNB

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The general prediction parameters and especially instruments will be heaped at zero but the treatment effect is real as per the simulation and we want the models to identify the true effect here, which they generally do

@@ -0,0 +1,2219 @@
{
Copy link
Collaborator

@drbenvincent drbenvincent Dec 5, 2025

Choose a reason for hiding this comment

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

Ah cool. So in this plot we do have the strong concentration on zero


Reply via ReviewNB

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes.

@@ -0,0 +1,2219 @@
{
Copy link
Collaborator

@drbenvincent drbenvincent Dec 5, 2025

Choose a reason for hiding this comment

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

Pedantic, but can you see these as subheadings rather than just bolded lines?


Reply via ReviewNB

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@drbenvincent drbenvincent changed the title Vs module Add variable selection priors Dec 5, 2025
@drbenvincent
Copy link
Collaborator

Added some comments on the new notebook. Not looked at the code yet.

Signed-off-by: Nathaniel <[email protected]>
@cursor
Copy link

cursor bot commented Dec 9, 2025

PR Summary

Introduces variable selection priors, integrates them into PyMC models and IV workflow, and adds tests and docs.

  • Modeling/Core:
    • Add causalpy/variable_selection_priors.py and integrate with PyMC in causalpy/pymc_models.py.
    • Update package exports in causalpy/__init__.py.
  • Experiments:
    • Update causalpy/experiments/instrumental_variable.py to work with variable selection priors.
  • Tests:
    • Add/expand PyMC integration examples in causalpy/tests/test_integration_pymc_examples.py.
    • Add tests for variable selection priors in causalpy/tests/test_variable_selection_priors.py.
  • Docs:
    • Add notebook docs/source/notebooks/iv_vs_priors.ipynb and index entry docs/source/notebooks/index.md.
    • Add docs/source/_static/interrogate_badge.svg.

Written by Cursor Bugbot for commit dbc8614. This will update automatically on new commits. Configure here.

Signed-off-by: Nathaniel <[email protected]>
the assumption of a simple IV experiment.
The coefficients should be interpreted appropriately."""
We will use the multivariate normal likelihood
for continuous treatment."""
Copy link

Choose a reason for hiding this comment

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

Bug: Validation warning ignores binary_treatment flag setting

The input_validation method checks if the treatment variable has more than 2 unique values and warns that "We will use the multivariate normal likelihood for continuous treatment." However, this warning doesn't account for the new binary_treatment parameter. If a user sets binary_treatment=True while having continuous treatment data, the warning incorrectly suggests MVN will be used, when actually the Bernoulli likelihood will be applied (which would fail on non-binary data). The validation needs to cross-check the actual data against the self.binary_treatment flag.

Fix in Cursor Fix in Web

Signed-off-by: Nathaniel <[email protected]>
Signed-off-by: Nathaniel <[email protected]>
Signed-off-by: Nathaniel <[email protected]>
mu=mu_outcome,
sigma=sigma_U,
observed=y.flatten(),
)
Copy link

Choose a reason for hiding this comment

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

Bug: Binary treatment likelihood has double noise specification

In the binary treatment model, the outcome equation has a double noise issue. The error term U (derived from eps[:, 0]) already contains variance from sigma_U through the Cholesky transformation. However, the outcome likelihood then adds another sigma_U noise term via pm.Normal("likelihood_outcome", mu=mu_outcome, sigma=sigma_U, ...). This effectively doubles the noise variance, making the model statistically incorrect. The latent error U should either be omitted from mu_outcome if using a Normal likelihood with sigma_U, or the likelihood should be changed to reflect that U is already the error component.

Fix in Cursor Fix in Web


# Cholesky decomposition for correlated errors
inverse_rho = pm.math.sqrt(pm.math.maximum(1 - rho_clipped**2, 1e-12))
chol = pt.stack([[sigma_U, 0.0], [sigma_U * rho_clipped, inverse_rho]])
Copy link

Choose a reason for hiding this comment

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

Bug: Cholesky decomposition has incorrect off-diagonal element

The Cholesky matrix for correlated errors in the binary treatment model is mathematically incorrect. The code constructs chol = [[sigma_U, 0], [sigma_U * rho_clipped, inverse_rho]], but for the intended covariance structure where the outcome error has variance sigma_U² and the treatment error has unit variance with correlation rho, the correct Cholesky should have [rho_clipped, inverse_rho] for the second row (not [sigma_U * rho_clipped, inverse_rho]). This produces an incorrect covariance matrix where the off-diagonal is sigma_U² * rho instead of sigma_U * rho, and the treatment variance is sigma_U² * rho² + 1 - rho² instead of 1.

Fix in Cursor Fix in Web

Signed-off-by: Nathaniel <[email protected]>
@NathanielF NathanielF closed this Dec 9, 2025
@NathanielF NathanielF reopened this Dec 9, 2025
@NathanielF
Copy link
Contributor Author

Great @NathanielF ! I think the notebooks need a bit more storyline and explanation 🙏

Took another pass @juanitorduz , should be more friendly now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants