causal_networkx.CPDAG#
- class causal_networkx.CPDAG(incoming_graph_data=None, incoming_uncertain_data=None, **attr)[source]#
Completed partially directed acyclic graphs (CPDAG).
CPDAGs generalize causal DAGs by allowing undirected edges. Undirected edges imply uncertainty in the orientation of the causal relationship. For example,
A - B
, can beA -> B
orA <- B
, allowing for a Markov equivalence class of DAGs for each CPDAG. This means that the number of DAGs represented by a CPDAG is $2^n$, wheren
is the number of undirected edges present in the CPDAG.- Parameters:
incoming_graph_data :
input
graph (optional, default:None
)Data to initialize directed edge graph. The edges in this graph represent directed edges between observed variables, which are represented using a
networkx.DiGraph
, so accepts any arguments from thenetworkx.DiGraph
class. There must be no cycles in this graph structure.incoming_uncertain_data :
input
graph (optional, default:None
)Data to initialize undirected edge graph. The edges in this graph represent undirected edges, which are represented using a
networkx.Graph
, so accepts any arguments from thenetworkx.Graph
class.
Notes
CPDAGs are Markov equivalence class of causal DAGs. The implicit assumption in these causal graphs are the Structural Causal Model (or SCM) is Markovian, inducing causal sufficiency, where there is no unobserved latent confounder. This allows CPDAGs to be learned from score-based (such as the GES algorithm) and constraint-based (such as the PC algorithm) approaches for causal structure learning.
One should not use CPDAGs if they suspect their data has unobserved latent confounders.
- Attributes:
-
Directed edges.
Name as a string identifier of the graph.
Return the nodes within the DAG.
Return the undirected edges of the graph.
Methods
add_chain
(node_chain)Add a causal chain.
add_edge
(u_of_edge, v_of_edge, **attr)Add an edge between u and v.
add_edges_from
(ebunch, **attr)Add directed edges.
add_node
(node_for_adding, **attr)Add node to causal graph.
add_nodes_from
(nodes_for_adding, **attr)Add nodes to causal graph.
add_undirected_edge
(u_of_edge, v_of_edge, **attr)Add a undirected edge between u and v.
add_undirected_edges_from
(ebunch, **attr)Add undirected edges in a bunch.
adjacencies
(u)Get all adjacent nodes to u.
Get dictionary of all the edges by edge type.
ancestors
(source)Ancestors of 'source' node with directed path.
children
(n)Return an iterator over children of node n.
clear
()Remove all nodes and edges in graphs.
Remove all edges from causal graph without removing nodes.
copy
()Return a copy of the causal graph.
degree
(n)Compute the degree of the DiGraph.
descendants
(source)Descendants of 'source' node with directed path.
draw
()Draws CPDAG graph.
Sample an empty dataframe with columns as the nodes.
get_edge_data
(u, v[, default])Get edge data from underlying DiGraph.
has_adjacency
(u, v)Check if there is any edge between u and v.
has_edge
(u, v)Check if graph has edge (u, v).
has_node
(n)Check if graph has node 'n'.
has_uncertain_edge
(u, v)Check if graph has undirected edge (u, v).
has_undirected_edge
(u, v)Check if graph has undirected edge (u, v).
In degree view of DAG.
Check if graph is acyclic.
is_node_common_cause
(node[, exclude_nodes])Check if a node is a common cause within the graph.
markov_blanket_of
(node)Compute the markov blanket of a node.
neighbors
(node)Neighbors view of DAG.
Return number of edges in graph.
Return number of nodes in graph.
number_of_undirected_edges
([u, v])Return number of undirected edges in graph.
order
()Return the order of the DiGraph.
orient_undirected_edge
(u, v)Orient undirected edge into an arrowhead.
Out degree view of DAG.
parents
(n)Return an iterator over parents of node n.
predecessors
(u)Return predecessors of node u.
relabel_nodes
(mapping[, copy])Relabel the nodes of the graph G according to a given mapping.
remove_edge
(u, v)Remove directed edge.
remove_edges_from
(ebunch)Remove directed edges.
remove_node
(n)Remove node in causal graphs.
remove_nodes_from
(ebunch)Remove nodes from causal graph.
remove_undirected_edge
(u, v)Remove circle edge from graph.
sample
([n])Sample from a graph.
Set nodes as latent unobserved confounders.
size
([weight])Return the total number of edges possibly with weights.
spouses
(node)Get other parents of the children of a node (spouses).
successors
(u)Return successors of node u.
Compute an adjacency undirected graph.
Convert CPDAG to a networkx DiGraph.
to_dot_graph
([to_dagitty])Convert to 'dot' graph representation as a string.
Converts causal graphs to networkx.
to_numpy
()Convert to a matrix representation.
compute_full_graph
is_directed
is_multigraph
possible_children
possible_parents
save
- __contains__(n)#
Return True if n is a node, False otherwise. Use: ‘n in G’.
Examples
>>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc >>> 1 in G True
- add_chain(node_chain)#
Add a causal chain.
- add_edge(u_of_edge, v_of_edge, **attr)#
Add an edge between u and v.
The nodes u and v will be automatically added if they are not already in the graph.
Edge attributes can be specified with keywords or by directly accessing the edge’s attribute dictionary. See examples below.
- Parameters:
u_of_edge, v_of_edge : nodes
Nodes can be, for example, strings or numbers. Nodes must be hashable (and not None) Python objects.
attr : keyword arguments, optional
Edge data (or labels or objects) can be assigned using keyword arguments.
See also
add_edges_from
add a collection of edges
Notes
Adding an edge that already exists updates the edge data.
Many NetworkX algorithms designed for weighted graphs use an edge attribute (by default
weight
) to hold a numerical value.Examples
The following all add the edge e=(1, 2) to graph G:
>>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc >>> e = (1, 2) >>> G.add_edge(1, 2) # explicit two-node form >>> G.add_edge(*e) # single edge as tuple of two nodes >>> G.add_edges_from([(1, 2)]) # add edges from iterable container
Associate data to edges using keywords:
>>> G.add_edge(1, 2, weight=3) >>> G.add_edge(1, 3, weight=7, capacity=15, length=342.7)
For non-string attribute keys, use subscript notation.
>>> G.add_edge(1, 2) >>> G[1][2].update({0: 5}) >>> G.edges[1, 2].update({0: 5})
- add_edges_from(ebunch, **attr)#
Add directed edges.
- add_node(node_for_adding, **attr)#
Add node to causal graph.
- add_nodes_from(nodes_for_adding, **attr)#
Add nodes to causal graph.
- add_undirected_edge(u_of_edge, v_of_edge, **attr)[source]#
Add a undirected edge between u and v.
The nodes u and v will be automatically added if they are not already in the graph. Moreover, they will be added to the underlying DiGraph, which stores all regular directed edges.
- Parameters:
u_of_edge, v_of_edge : nodes
Nodes can be, for example, strings or numbers. Nodes must be hashable (and not None) Python objects.
attr : keyword arguments, optional
Edge data (or labels or objects) can be assigned using keyword arguments.
See also
networkx.Graph.add_edges_from
add a collection of edges
networkx.Graph.add_edge
add an edge
Notes
…
- Return type:
- adjacencies(u)#
Get all adjacent nodes to u.
Adjacencies are defined as any type of edge to node ‘u’.
- all_edges()#
Get dictionary of all the edges by edge type.
- ancestors(source)#
Ancestors of ‘source’ node with directed path.
- children(n)#
Return an iterator over children of node n.
Children of node ‘n’ are nodes with a directed edge from ‘n’ to that node. For example, ‘n’ -> ‘x’, ‘n’ -> ‘y’. Nodes only connected via a bidirected edge are not considered children: ‘n’ <-> ‘y’.
- Parameters:
n : node
A node in the causal DAG.
- Returns:
children :
Iterator
An iterator of the children of node ‘n’.
- clear()#
Remove all nodes and edges in graphs.
- clear_edges()#
Remove all edges from causal graph without removing nodes.
Clears edges in the DiGraph and the bidirected undirected graph.
- copy()#
Return a copy of the causal graph.
- degree(n)#
Compute the degree of the DiGraph.
- descendants(source)#
Descendants of ‘source’ node with directed path.
- draw()[source]#
Draws CPDAG graph.
For custom parametrizations, use
graphviz
ornetworkx
drawers directly with theself.dag
andself.c_component_graph
.
- dummy_sample()#
Sample an empty dataframe with columns as the nodes.
Used for oracle testing.
- property edges#
Directed edges.
- get_edge_data(u, v, default=None)#
Get edge data from underlying DiGraph.
- has_adjacency(u, v)#
Check if there is any edge between u and v.
- has_edge(u, v)#
Check if graph has edge (u, v).
- has_node(n)#
Check if graph has node ‘n’.
- in_degree()#
In degree view of DAG.
- is_acyclic()#
Check if graph is acyclic.
- is_node_common_cause(node, exclude_nodes=None)#
Check if a node is a common cause within the graph.
- markov_blanket_of(node)#
Compute the markov blanket of a node.
When computing the Markov blanket for an ADMG, we can use the definition presented in [1], where the Markov blanket is a subset,
S
of variables in the graph, where a subset,S'
is called a Markov blanket if it satisfies the condition:\[X \perp S | S'\]- Parameters:
node : node
The node to compute Markov blanket for.
- Returns:
markov_blanket :
set
A set of parents, children and spouses of the node.
References
- Return type:
- property name#
Name as a string identifier of the graph.
This graph attribute appears in the attribute dict G.graph keyed by the string “name”. as well as an attribute (technically a property)
G.name
. This is entirely user controlled.
- neighbors(node)#
Neighbors view of DAG.
- property nodes#
Return the nodes within the DAG.
Ignores the c-component graph nodes.
- number_of_edges()#
Return number of edges in graph.
- number_of_nodes()#
Return number of nodes in graph.
- order()#
Return the order of the DiGraph.
- orient_undirected_edge(u, v)[source]#
Orient undirected edge into an arrowhead.
If there is an undirected edge u - v, then the arrowhead will orient u -> v. If the correct order is v <- u, then simply pass the arguments in different order.
- Parameters:
u : node
The parent node
v : node
The node that ‘u’ points to in the graph.
- out_degree()#
Out degree view of DAG.
- parents(n)#
Return an iterator over parents of node n.
Parents of node ‘n’ are nodes with a directed edge from ‘n’ to that node. For example, ‘n’ <- ‘x’, ‘n’ <- ‘y’. Nodes only connected via a bidirected edge are not considered parents: ‘n’ <-> ‘y’.
- Parameters:
n : node
A node in the causal DAG.
- Returns:
parents :
Iterator
An iterator of the parents of node ‘n’.
- predecessors(u)#
Return predecessors of node u.
A predecessor is defined as nodes with a directed edge to ‘u’. That is ‘v’ -> ‘u’. A bidirected edge would not qualify as a predecessor.
- relabel_nodes(mapping, copy=True)#
Relabel the nodes of the graph G according to a given mapping.
- Parameters:
mapping :
dict
A dictionary with the old labels as keys and new labels as values. A partial mapping is allowed. Mapping 2 nodes to a single node is allowed. Any non-node keys in the mapping are ignored.
copy : bool (optional, default=True)
If True return a copy, or if False relabel the nodes in place.
- Returns:
G : instance of causal
DAG
A copy (if copy is True) of the relabeled graph.
- remove_edge(u, v)#
Remove directed edge.
- remove_edges_from(ebunch)#
Remove directed edges.
- remove_node(n)#
Remove node in causal graphs.
- remove_nodes_from(ebunch)#
Remove nodes from causal graph.
- sample(n=1000)#
Sample from a graph.
- set_nodes_as_latent_confounders(nodes)#
Set nodes as latent unobserved confounders.
Note that this only works if the original node is a common cause of some variables in the graph.
- size(weight=None)#
Return the total number of edges possibly with weights.
- successors(u)#
Return successors of node u.
A successor is defined as nodes with a directed edge from ‘u’. That is ‘u’ -> ‘v’. A bidirected edge would not qualify as a successor.
- to_adjacency_graph()#
Compute an adjacency undirected graph.
Two nodes are considered adjacent if there exist any type of edge between the two nodes.
- Return type:
- to_directed()[source]#
Convert CPDAG to a networkx DiGraph.
Undirected edges are converted to a ‘->’ and ‘<-’ edge in the DiGraph. Note that the resulting DiGraph is not “acyclic” anymore.
- to_dot_graph(to_dagitty=False)#
Convert to ‘dot’ graph representation as a string.
The DOT language for graphviz is what is commonly used in R’s
dagitty
package. This is a string representation of the graph. However, this converts to a string format that is not 100% representative of DOT [1]. See Notes for more information.- Parameters:
to_dagitty : bool
Whether to conform to the Dagitty format, where the string begins with
dag {
instead ofstrict digraph {
.- Returns:
dot_graph :
str
A string representation in DOT format for the graph.
Notes
The output of this function can be immediately plugged into the dagitty online portal for drawing a graph.
For example, if we have a mixed edge graph, with directed and bidirected arrows (i.e. a causal DAG). Specifically, if we had
0 -> 1
with a latent confounder, we would get the following output:strict digraph { 0; 1; 0 -> 1; 0 <-> 1; }
To represent for example a bidirected edge,
A <-> B
, the DOT format would make you useA -> B [dir=both]
, but this is not as intuitive.A <-> B
also complies with dagitty and other approaches to drawing graphs in Python/R.References
- to_networkx()#
Converts causal graphs to networkx.
- to_numpy()#
Convert to a matrix representation.
A single 2D numpy array is returned, since a PAG only maps one edge between any two nodes.
- Returns:
numpy_graph :
np.ndarray
of shape (n_nodes, n_nodes)The causal graph with values specified as a string character. For example, if A has a directed edge to B, then the array at indices for A and B has
'->'
.
Notes
In R’s
pcalg
package, the following encodes the types of edges as an array. We will follow the same encoding for our numpy array representation.References
- property undirected_edges#
Return the undirected edges of the graph.