class examples:
"""
Retrieve a predefined example DAG or list available examples.
Parameters
----------
which : str or None, optional
Name of the example to load. When ``None``, the function prints the
list of available examples (optionally with their DAG representations)
and returns ``None``.
print_DAG : bool, optional
If ``True`` and ``which`` is ``None``, print the textual
representation of each example DAG. Defaults to ``False``.
*args :
Additional positional arguments forwarded to the example factory.
**kws :
Additional keyword arguments forwarded to the example factory.
Returns
-------
DAG or None
Instantiated `DAG` object when ``which`` matches an example; otherwise
``None``.
Examples
--------
>>> examples() # print the list of predefined examples
>>> G = examples('Frontdoor') # load DAG from predefined example
>>> isinstance(G, DAG)
True
"""
def __new__(cls, which=None, print_DAG=False, *args: Any, **kws: Any):
if not which:
examples._print_examples(print_DAG=print_DAG)
dag = None
else:
try:
dag = examples._get_examples(which, *args, **kws)
except KeyError:
# friendly suggestion for typos
suggestion = difflib.get_close_matches(which, examples._get_examples().keys(), n=3, cutoff=0.4)
hint = f" Did you mean: {', '.join(suggestion)}?" if suggestion else ""
raise ValueError(f"Unknown example '{which}'.{hint}")
return DAG(**dag) if dag else None
def _get_examples(which=None, *args, **kws):
all_examples = {
"Not identifiable" : examples._example_not_identifiable(*args, **kws),
"One confounder" : examples._example_one_confounder(*args, **kws),
"Two confounders" : examples._example_two_confounder(*args, **kws),
"Front-door" : examples._example_front_door(*args, **kws),
"IV with 1 instrument" : examples._example_iv_1_instrument(*args, **kws),
"IV with 3 instruments" : examples._example_iv_3_instruments(*args, **kws),
"SoO, IV, and do identified with 1 confounder": examples._example_soo_iv_do_one_counfounder(*args,
**kws),
"Mediation: 2 sequential 1 confounder" : examples._example_mediation_2_sequential_1_confounder(*args,
**kws),
# "Back-door": self._back_door(),
# Pearl's book
"Pearl Example 1.1 (a)" : examples._example_pearl_fig_1_1_a(*args, **kws),
"Pearl Example 1.1 (b)" : examples._example_pearl_fig_1_1_b(*args, **kws),
"Pearl Example 1.2" : examples._example_pearl_fig_1_2(*args, **kws),
"Pearl Example 1.3 (a)" : examples._example_pearl_fig_1_3_a(*args, **kws),
"Pearl Example 1.3 (b)" : examples._example_pearl_fig_1_3_b(*args, **kws),
"Pearl Example 3.1" : examples._example_pearl_fig_3_1(*args, **kws),
"Pearl Example 3.4" : examples._example_pearl_fig_3_4(*args, **kws),
"Pearl Example 3.5" : examples._example_pearl_fig_3_5(*args, **kws),
}
res = all_examples[which] if which else all_examples
return res
def _print_examples(print_DAG):
print(dedent("""
List of available examples:
--------------------------\
"""))
for i, (name, example) in enumerate(examples._get_examples().items()):
print(f"{i+1}. {name}")
if print_DAG:
print(DAG(**example))
print(f"\nUsage: examples(which='<example name>')"+
f"\nExample: G = examples(which='{name}')")
if not print_DAG:
print("Note: To print the associated DAG of each example, use examples(print_DAG=True)")
return None
def _example_not_identifiable(*args, **kws):
dag = """
D -> Y
D <-> Y
Z -> {D, Y}
"""
pos = {"D": (0, 0), "Y": (1, 0), "Z": (0.5, 1)}
roles = {"Exposure": "D", "Outcome": "Y"}
labels = None
return dict(graph=dag, nodes_role=roles, nodes_position=pos, nodes_label=labels)
def _example_one_confounder(*args, **kws):
dag = """
D -> Y
Z1 -> {D, Y}
"""
pos = {"D": (0, 0), "Y": (1, 0), "Z1": (0.5, 1)}
roles = {"Exposure": "D", "Outcome": "Y"}
labels = {'Z1':"$Z_1$"}
return dict(graph=dag, nodes_role=roles, nodes_position=pos, nodes_label=labels)
def _example_two_confounder(*args, **kws):
dag = """
D -> Y
Z1 -> {D, Y}
Z2 -> {D, Y}
"""
pos = {"D": (0, 0), "Y": (1, 0), "Z1": (0.5, 1), "Z2": (0.5, -1)}
roles = {"Exposure": "D", "Outcome": "Y"}
labels = {'Z2':"$Z_2$", 'Z1':"$Z_1$"}
return dict(graph=dag, nodes_role=roles, nodes_position=pos, nodes_label=labels)
def _example_front_door(*args, **kws):
dag = """
U -> {D, Y}
D -> Z -> Y
Z2 -> {D, Y}
"""
pos = {'D': (0 , 0),
'Z': (.5, 0),
'Y': (1 , 0),
'U': (.5, 1),
'Z2': (.5, -1),
}
roles = {'Exposure': "D",
'Outcome' : "Y",
"Latent" : "U"
}
labels = {'Z2':"$Z_2$"}
return dict(graph=dag, nodes_role=roles, nodes_position=pos, nodes_label=labels)
def _example_iv_1_instrument(*args, **kws):
dag = """
X <-> Y
Z -> X -> Y
"""
pos = {'Z': ( 0, 0),
'X': ( .5, -1),
"Y": ( 1,-2)}
roles = {'Exposure': "X",
'Outcome' : "Y"}
edge_labels = {('Z', 'X'): "$\\beta$",
('X', 'Y'): "$\\alpha$"}
labels = None
return dict(graph=dag, nodes_role=roles, nodes_position=pos, nodes_label=labels,
edge_label=edge_labels)
def _example_iv_3_instruments(*args, **kws):
dag = """
D <-> Y
Z1 -> D -> Y
D <- X1 -> Y
Z1<- Z2 -> Y
Z1<- Z3 -> D
Z1-> Z4 <- X2 -> Y
"""
pos = {'D': ( 0, 0),
"Y": ( 1, 0),
'Z1': (-1, 0),
"Z2": (0,-.5),
"Z3": (-.5, 1),
"Z4": (-.5,-1),
"X2": ( .5,-1),
"X1": (.5, 1),
}
roles = {'Exposure': "D",
'Outcome' : "Y"}
edge_labels = None
labels = {'X1': '$X_1$',
'X2': '$X_2$',
'Z1': '$Z_1$',
'Z2': '$Z_2$',
'Z3': '$Z_3$',
'Z4': '$Z_4$',
}
return dict(graph=dag, nodes_role=roles, nodes_position=pos, nodes_label=labels,
edge_label=edge_labels)
def _example_soo_iv_do_one_counfounder(*args, **kws):
dag = """
Z -> D -> Y
D <- X1 -> Y
Z <- X2 -> Y
"""
pos = {'D': ( 0, 0),
"Y": ( 1, 0),
'Z': (-1, 0),
"X2": ( .5,-1),
"X1": (.5, 1),
}
roles = {'Exposure': "D",
'Outcome' : "Y"}
edge_labels = None
labels = {'X1': '$X_1$',
'X2': '$X_2$',
}
return dict(graph=dag, nodes_role=roles, nodes_position=pos, nodes_label=labels,
edge_label=edge_labels)
def _example_mediation_2_sequential_1_confounder(*args, **kws):
dag = """
D -> M1 -> M2 -> Y
D -> Y
D <- Z -> Y
"""
pos = {'D' : (0 , 0),
'M1': (.5, 1),
'M2': ( 1, 1),
'Y' : (1.5 , 0),
'Z': (.75, -1),
}
roles = {'Exposure': "D",
'Outcome' : "Y",
}
labels = {"M1":'$M_1$',
"M2":'$M_2$',
}
return dict(graph=dag, nodes_role=roles, nodes_position=pos, nodes_label=labels)
def _example_pearl_fig_1_1_a(*args, **kws):
# """
# Source:
# - Pearl, J. (2009). Causality: Models, Reasoning and Inference. : Cambridge University Press.
# """
dag = """
W -> Z -> Y
Z <-> X -> Y
"""
pos = {'Z': ( 0, 0),
'X': ( 1, 0),
"Y": ( .5,-1),
'W': ( 0, 1),
}
roles = {'Exposure': "X",
'Outcome' : "Y"
}
edge_labels = None
labels = None
return dict(graph=dag, nodes_role=roles, nodes_position=pos, nodes_label=labels,
edge_label=edge_labels)
def _example_pearl_fig_1_1_b(*args, **kws):
# """
# Source:
# - Pearl, J. (2009). Causality: Models, Reasoning and Inference. : Cambridge University Press.
# """
dag = """
Z -> {W, Z, Y}
Y -> X
"""
pos = {'Z': ( 0, 0),
'X': ( 1, 0),
"Y": ( .5,-1),
'W': ( 0, 1),
}
roles = {'Exposure': "Z",
'Outcome' : "Y"
}
edge_labels = None
labels = None
return dict(graph=dag, nodes_role=roles, nodes_position=pos, nodes_label=labels,
edge_label=edge_labels)
def _example_pearl_fig_1_2(*args, **kws):
# """
# Source:
# - Pearl, J. (2009). Causality: Models, Reasoning and Inference. : Cambridge University Press.
# """
dag = """
X1 -> {X2, X3} -> X4 -> X5
"""
pos = {"X1": ( 0, 0),
"X2": ( 1, -1),
"X3": ( -1,-1),
"X4": ( 0, -2),
"X5": ( 0, -3),
}
roles = {'Exposure': "X1",
'Outcome' : "X5"
}
edge_labels = None
labels = {"X1" : 'X1 (Season)',
"X2" : "X2 (Rain)",
"X3" : "X3 (Sprinkler)",
"X4" : 'X4 (Wet)',
"X5" : 'X5 (Slippery)'
}
return dict(graph=dag, nodes_role=roles, nodes_position=pos, nodes_label=labels,
edge_label=edge_labels)
def _example_pearl_fig_1_3_a(*args, **kws):
# """
# Source:
# - Pearl, J. (2009). Causality: Models, Reasoning and Inference. : Cambridge University Press.
# """
dag = """
X -> Z1 <- Z2 <- Z3 <- Y
Z1 <-> Z3
"""
pos = {"X": (0 ,0),
"Z1": (1 ,0),
"Z2": (2 ,0),
"Z3": (3 ,0),
"Y" : (4 ,0),
}
roles = {'Exposure': "X",
'Outcome' : "Y"
}
edge_labels = None
labels = None
return dict(graph=dag, nodes_role=roles, nodes_position=pos, nodes_label=labels,
edge_label=edge_labels)
def _example_pearl_fig_1_3_b(*args, **kws):
# """
# Source:
# - Pearl, J. (2009). Causality: Models, Reasoning and Inference. : Cambridge University Press.
# """
dag = """
X -> Z2 -> Z1 -> X
Y -> Z2
"""
pos = {"X": (0 ,0),
"Z1": (1 ,1),
"Z2": (2 ,0),
"Y" : (3 ,0),
}
roles = {'Exposure': "X",
'Outcome' : "Y"
}
edge_labels = None
labels = None
return dict(graph=dag, nodes_role=roles, nodes_position=pos, nodes_label=labels,
edge_label=edge_labels)
def _example_pearl_fig_3_1(*args, **kws):
# """
# Source:
# - Pearl, J. (2009). Causality: Models, Reasoning and Inference. : Cambridge University Press.
# """
dag = """
X -> {Z2, Y}
Z2 -> {Z3, Y}
Z3 -> Y
Z1 -> Z2
B -> Z3
Z0 -> {X, Z1, B}
"""
pos = {"X": (0 ,0),
"Z0": (1 ,1),
"Z1": (1 ,.5),
"Z2": (1 ,0),
"Z3": (2 ,0),
"B": (1.5 ,.5),
"Y" : (1 ,-.5),
}
roles = {'Exposure': "X",
'Outcome' : "Y",
'Latent' : ['Z0', 'B']
}
edge_labels = None
labels = {"Z0": "$Z_0$",
"Z1": "$Z_1$",
"Z2": "$Z_2$",
"Z3": "$Z_3$",
}
return dict(graph=dag, nodes_role=roles, nodes_position=pos, nodes_label=labels,
edge_label=edge_labels)
def _example_pearl_fig_3_4(*args, **kws):
# """
# Source:
# - Pearl, J. (2009). Causality: Models, Reasoning and Inference. : Cambridge University Press.
# """
dag = """
X1 -> {X3, X4}
X2 -> {X4, X5}
X3 -> Xi
X4 -> {Xi, Xj}
X5 -> Xj
X6 -> Xj
Xi -> X6
"""
pos = {"Xi": (0, 0),
'Xj': (2, 0),
"X1": (0, 2),
"X2": (2, 2),
"X3": (0, 1),
"X4": (1, 1),
"X5": (2, 1),
"X6": (1, 0),
}
roles = {'Exposure': "Xi",
'Outcome' : "Xj",
}
edge_labels = None
labels = {"Xi": "$X_i$",
"Xj": "$X_j$",
"X1": "$X_1$",
"X2": "$X_2$",
"X3": "$X_3$",
"X4": "$X_4$",
"X5": "$X_5$",
"X6": "$X_6$",
}
return dict(graph=dag, nodes_role=roles, nodes_position=pos, nodes_label=labels,
edge_label=edge_labels)
def _example_pearl_fig_3_5(*args, **kws):
dag = """
U -> {X, Y}
X -> Z -> Y
"""
pos = {'X': (0 , 0),
'Z': (.5, 0),
'Y': (1 , 0),
'U': (.5, 1),
}
roles = {'Exposure': "X",
'Outcome' : "Y",
"Latent" : "U"
}
labels = None
return dict(graph=dag, nodes_role=roles, nodes_position=pos, nodes_label=labels)