py-why / dowhy

DoWhy is a Python library for causal inference that supports explicit modeling and testing of causal assumptions. DoWhy is based on a unified language for causal inference, combining causal graphical models and potential outcomes frameworks.
https://www.pywhy.org/dowhy
MIT License
7.14k stars 935 forks source link

Order of Action Nodes effects Identified Estimand #1250

Open nparent1 opened 2 months ago

nparent1 commented 2 months ago

DoWhy's has_directed_path method checks for a directed path between the action node at index 0, and outcome node at index 0. AutoIdentifier's identify_effect_auto method exits if there is no directed path.

Thus, if you call identify_effect_auto() with two action nodes, where one has a path to the (first) outcome node and the other does not, then you get different results.

The following two code snippets have one different line, action_nodes= ['treatment', 'independent_variable'] vs action_nodes= ['independent_variable', 'treatment']

The first:

from dowhy.causal_identifier import AutoIdentifier, EstimandType
Identifier = AutoIdentifier(EstimandType.NONPARAMETRIC_ATE)
causal_graph = """digraph {
treatment;
independent_variable;
outcome;
treatment->outcome;
}"""
G = to_nx_graph(causal_graph)   # code for to_nx_graph not in snippet
eff = Identifier.identify_effect(
    G,
    action_nodes= ['treatment', 'independent_variable'],
    outcome_nodes= ['outcome'],
    observed_nodes= ['treatment', 'independent_variable', 'outcome'],
)
print(eff)

This gives back

image

The second:

from dowhy.causal_identifier import AutoIdentifier, EstimandType
Identifier = AutoIdentifier(EstimandType.NONPARAMETRIC_ATE)
causal_graph = """digraph {
treatment;
independent_variable;
outcome;
treatment->outcome;
}"""
G = to_nx_graph(causal_graph)   # code for to_nx_graph not in snippet
eff = Identifier.identify_effect(
    G,
    action_nodes= ['independent_variable', 'treatment'],
    outcome_nodes= ['outcome'],
    observed_nodes= ['treatment', 'independent_variable', 'outcome'],
)
print(eff)

This gives back

image

nparent1 commented 2 months ago

I noticed this when working on #654 in https://github.com/py-why/dowhy/pull/1247

I believe that PR should also fix this issue, but wanted to open a separate issue in case it was preferred this got resolved another way