Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEA] Generalized Adjustment Criterion #1292

Open
wants to merge 15 commits into
base: main
Choose a base branch
from

Conversation

nparent1
Copy link
Contributor

@nparent1 nparent1 commented Dec 30, 2024

Relates to feature #402

This PR adds support for identifying generalized (non-backdoor) adjustment sets. Specifically, it adds support for finding a minimal adjustment set if one exists (it is guaranteed to find a set if one does exist). Ongoing work in the pywhy-graphs library to enumerate all m-separating sets in causal graphs will later unlock the ability to enumerate all generalized adjustment sets.

The PR roughly adds the following

  • A new field to the IdentifiedEstimand class to store general adjustment sets (given how ubiquitous the backdoor criterion is I left the backdoor fields alone and created new fields for these general sets)
  • Support in the auto_identifier.py file's identify_ate_effect() method to compute a general adjustment set to return in an IdentifiedEstimand object
    • Finding the adjustment set is all handled in a new identify_generalized_adjustment_set() method
  • Refactoring to share various utility functions between the backdoor adjustment sets and the general adjustment sets
  • Unit tests to test a few cases of the generalized adjustment criterion (specifically cases where the backdoor criterion is not met)

In a subsequent PR I can add support for these general adjustment sets in the causal estimation stage.

References:

Benito van der Zander, Maciej Liśkiewicz, and Johannes Textor. "Constructing Separators and
Adjustment Sets in Ancestral Graphs." In Proceedings of UAI 2014, pages 907–916,
2014.

Signed-off-by: Nicholas Parente <[email protected]>
Signed-off-by: Nicholas Parente <[email protected]>
Signed-off-by: Nicholas Parente <[email protected]>
Signed-off-by: Nicholas Parente <[email protected]>
Signed-off-by: Nicholas Parente <[email protected]>
@nparent1 nparent1 changed the title [WIP] General Adjustment Generalized Adjustment Criterion Dec 30, 2024
@nparent1 nparent1 changed the title Generalized Adjustment Criterion [FEA] Generalized Adjustment Criterion Dec 30, 2024
Signed-off-by: Nicholas Parente <[email protected]>
Signed-off-by: Nicholas Parente <[email protected]>
@nparent1 nparent1 marked this pull request as draft December 30, 2024 23:15
Signed-off-by: Nicholas Parente <[email protected]>
Signed-off-by: Nicholas Parente <[email protected]>
Signed-off-by: Nicholas Parente <[email protected]>
@nparent1 nparent1 marked this pull request as ready for review December 31, 2024 05:38
@amit-sharma amit-sharma self-requested a review December 31, 2024 07:50
Copy link
Member

@amit-sharma amit-sharma left a comment

Choose a reason for hiding this comment

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

Thanks for starting this @nparent1
Two requests as I review this PR:

  1. Can you add a notebook showing how the new feature can be used? you can add a notebook under docs/source/example_notebooks/. As examples, you can refer to this notebook on ID algorithm or the optimal adjustment criterion. It will be ideal if the notebook can contrast with the output of the backdoor criterion and show when the generalized adjustment criterion is useful.
  2. Can you add documentation to all the user-facing functions? You can refer to auto-identifier.py or other files. I would suggest adding :param: and :returns: documentation for the functions at the minimum.

Signed-off-by: Nicholas Parente <[email protected]>
@nparent1 nparent1 force-pushed the np/gen_adjustment_two branch from 9972173 to e275326 Compare January 3, 2025 17:37
Signed-off-by: Nicholas Parente <[email protected]>
@nparent1
Copy link
Contributor Author

nparent1 commented Jan 3, 2025

Done! @amit-sharma

I've added an example notebook and documentation.

The example notebook is at: docs/source/example_notebooks/dowhy_generalized_covariate_adjustment_example.ipynb

The only user-facing function I had envisioned at this point was the identify_effect_auto() method in auto_identifier.py (and CausalModel's identify_effect() method, but my changes don't touch its method header). I also added documentation to my two utility functions in the graph.py file though, since I saw some of those methods have detailed documentation.

One other flag - in putting together the notebook I think I found a small bug in the frontdoor criterion codepath, which I've addressed in this PR since it prevented me from running identify_effect() on my example graph (I'll add a comment to the PR pointing out the change so you can verify that it is appropriate)

@@ -795,7 +847,10 @@ def identify_frontdoor(
raise ValueError(f"d-separation algorithm {dseparation_algo} is not supported")

eligible_variables = (
get_descendants(graph, action_nodes) - set(outcome_nodes) - set(get_descendants(graph, outcome_nodes))
get_descendants(graph, action_nodes)
- set(action_nodes)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added this line to remove the action nodes from the set of eligible nodes (and added a unit test which illustrates why this is needed). If there are multiple action nodes and one of them ends up in the list of eligible variables, we can run into a networkx error when calling the is_d_separator method, in which we are checking if one of the action nodes is a d-separator for the set of action nodes

@@ -422,4 +483,15 @@
valid_frontdoor_sets=[],
invalid_frontdoor_sets=[{"Z"}, {"M1"}, {"M2"}, {"M1", "M2"}],
),
# This example is reproduced from the generalized_adjustment examples, and is
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here is the unit test I've added to illustrate why we need to filter out the action nodes from the set of eligible notes for the frontdoor criterion (without my change this test throws an error)

@nparent1 nparent1 requested a review from amit-sharma January 4, 2025 02:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants