Draw Causal Graph

Import and settings

In this example, we need to import numpy, pandas, and graphviz in addition to lingam. And to draw the causal graph, we need to import make_dot method from lingam.utils.

import numpy as np
import pandas as pd
import graphviz
import lingam
from lingam.utils import make_dot

print([np.__version__, pd.__version__, graphviz.__version__, lingam.__version__])

np.set_printoptions(precision=3, suppress=True)
np.random.seed(0)
['1.16.2', '0.24.2', '0.11.1', '1.3.1']

Draw the result of LiNGAM

First, we can draw a simple graph that is the result of LiNGAM.

x3 = np.random.uniform(size=10000)
x0 = 3.0*x3 + np.random.uniform(size=10000)
x2 = 6.0*x3 + np.random.uniform(size=10000)
x1 = 3.0*x0 + 2.0*x2 + np.random.uniform(size=10000)
x5 = 4.0*x0 + np.random.uniform(size=10000)
x4 = 8.0*x0 - 1.0*x2 + np.random.uniform(size=10000)
X = pd.DataFrame(np.array([x0, x1, x2, x3, x4, x5]).T ,columns=['x0', 'x1', 'x2', 'x3', 'x4', 'x5'])

model = lingam.DirectLiNGAM()
model.fit(X)
make_dot(model.adjacency_matrix_)
../_images/draw_graph1.svg

If we want to change the variable name, we can use labels.

labels = [f'var{i}' for i in range(X.shape[1])]
make_dot(model.adjacency_matrix_, labels=labels)
../_images/draw_graph2.svg

Save graph

The created dot data can be saved as an image file in addition to being displayed in Jupyter Notebook.

dot = make_dot(model.adjacency_matrix_, labels=labels)

# Save pdf
dot.render('dag')

# Save png
dot.format = 'png'
dot.render('dag')
'dag.png'

Draw the result of LiNGAM with prediction model

For example, we create a linear regression model with x0 as the target variable.

from sklearn.linear_model import LinearRegression

target = 0
features = [i for i in range(X.shape[1]) if i != target]
reg = LinearRegression()

reg.fit(X.iloc[:, features], X.iloc[:, target])
LinearRegression(copy_X=True, fit_intercept=True, n_jobs=None,
         normalize=False)

By specify prediction_feature_indices and prediction_coefs that can be obtained from the prediction model, we can draw the prediction model with the causal structure.

make_dot(model.adjacency_matrix_, prediction_feature_indices=features, prediction_coefs=reg.coef_)
../_images/draw_graph3.svg

Also, we can change the label of the target variable by prediction_target_label, omit the coefficient of prediction model without prediction_coefs, and change the color by prediction_line_color.

make_dot(model.adjacency_matrix_, prediction_feature_indices=features, prediction_target_label='Target', prediction_line_color='#0000FF')
../_images/draw_graph4.svg

In addition to the above, we can use prediction_feature_importance to draw the importance of the prediction model as an edge label.

import lightgbm as lgb

target = 0
features = [i for i in range(X.shape[1]) if i != target]
reg = lgb.LGBMRegressor(random_state=0)
reg.fit(X.iloc[:, features], X.iloc[:, target])
reg.feature_importances_
array([619, 205, 310, 957, 909])
make_dot(model.adjacency_matrix_, prediction_feature_indices=features, prediction_feature_importance=reg.feature_importances_)
../_images/draw_graph5.svg

Highlight paths between specified nodes

make_dot highlights the path specified by the path argument.

make_dot(model.adjacency_matrix_, path=(3, 1))
../_images/draw_graph13.svg

If detect_cycles is True, simple cycles are displayed with a dashed edge.

result = model.adjacency_matrix_.copy()
result[0, 1] = 100
result[3, 1] = 100

make_dot(result, path=(3, 1), path_color="red", detect_cycle=True)
../_images/draw_graph14.svg

Draw the result of LiNGAM with emphasis on descendants and ancestors

make_dot_highlight highlights descendants or ancestors of the graph.

The first argument is the result and the second argument is the index of the target variable. There are four types of cluster names: target, ancestor, descendant, and others. target contains only the node specified in the second argument. Nodes that are ancestors or descendants of target belong to ancestor or descendant. The number appended to the cluster name is the distance from target. Other nodes belong to others.

make_dot_highlight(model.adjacency_matrix_, 0)
../_images/draw_graph6.svg

It is also possible to disable the display of clusters of ancestors and descendants.

make_dot_highlight(model.adjacency_matrix_, 0, max_dsc=0, max_anc=None)
../_images/draw_graph7.svg

It is also possible to suppress the display of the others cluster.

make_dot_highlight(model.adjacency_matrix_, 0, max_dsc=0, max_anc=None, draw_others=False)
../_images/draw_graph8.svg

Draw the result of Bootstrap with emphasis on descendants and ancestors

It is possible to visualize results that include the cyclic portion, such as the result of a bootstrap.

result = model.bootstrap(X, n_sampling=100)
median = np.median(result.adjacency_matrices_, axis=0)
make_dot(median, lower_limit=0)
../_images/draw_graph9.svg

Applying make_dot_highlight to this graph draws the following graph. Dashed edges indicate simple cycles.

make_dot_highlight(median, 0, detect_cycle=True)
../_images/draw_graph10.svg

You can reduce the edges by setting lower_limit.

make_dot_highlight(median, 0, detect_cycle=True, lower_limit=0.1)
../_images/draw_graph11.svg

You can also set the color map and the spacing of the nodes.

make_dot_highlight(median, 0, lower_limit=0.001, cmap="cool", vmargin=3, hmargin=3)
../_images/draw_graph12.svg