BottomUpParceLiNGAM/CAM-UV

Python

diabetesデータセットを使ってBottomUpParceLiNGAM/CAM-UVで因果探索をやってみたメモです。

LiNGAMチュートリアル

https://lingam.readthedocs.io/en/latest/reference/bottom_up_parce_lingam.html

https://lingam.readthedocs.io/en/latest/tutorial/camuv.html

参考

https://qiita.com/kirikei/items/3a47aecc317d6a580fbf

diabetesデータセット

https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_diabetes.html#sklearn.datasets.load_diabetes

 

 

内容

準備
# ライブラリインポート
import pandas as pd
import numpy as np

from sklearn.datasets import load_diabetes
from sklearn.preprocessing import StandardScaler

import graphviz
import lingam
from lingam.utils import make_dot, make_prior_knowledge

# データセット読み込み
dataset = load_diabetes(as_frame=True)['data'][['age', 'sex', 'bmi', 'bp']]
dataset['target'] = load_diabetes(as_frame=True)['target']
dataset.head()

       age	   sex	   bmi	   bp	target
0	0.038076	0.050680	0.061696	0.021872	151.0
1	-0.001882	-0.044642	-0.051474	-0.026328	75.0
2	0.085299	0.050680	0.044451	-0.005671	141.0
3	-0.089063	-0.044642	-0.011595	-0.036656	206.0
4	0.005383	-0.044642	-0.036385	0.021872	135.0

BottomUpParceLiNGAMで因果探索

BottomUpParceLiNGAMでは、未観測共通原因を考慮して因果探索ができます。未観測共通原因を有する変数ペアは、両矢印↔で表現されます。文献は以下です。

https://direct.mit.edu/neco/article-abstract/26/1/57/7935/ParceLiNGAM-A-Causal-Ordering-Method-Robust?redirectedFrom=fulltext

https://arxiv.org/abs/1303.7410

# 標準化
scaler = StandardScaler()
Xy = scaler.fit_transform(dataset)

# モデル作成
model = lingam.BottomUpParceLiNGAM(random_state=1)
model.fit(Xy)

# 因果の順番
print(model.causal_order_)

# 隣接行列
print(model.adjacency_matrix_)
[[0, 1, 2, 4], 3]

[[0.                nan        nan 0.                nan]
 [       nan 0.                nan 0.                nan]
 [       nan        nan 0.         0.                nan]
 [0.2186471  0.17565042 0.16626303 0.         0.29533368]
 [       nan        nan        nan 0.         0.        ]]

 

# 因果グラフの描画
# 以下よりgraphvizのexeをインストールする。インストール時にpathに追加する。
# https://graphviz.org/download/

dot = make_dot(model.adjacency_matrix_, labels=dataset.columns.to_list())
dot.format = 'png'
dot.render('BottomUpParceLiNGAM')
dot

4つの変数について、未観測共通原因を持つモデルが推定されました。説明変数Xについては、diabetesデータセットの一部しか使用していないため、その影響もあるのかもしれません。

 

時前知識の導入

BottomUpParceLiNGAMでは事前知識を導入することができます。

https://lingam.readthedocs.io/en/latest/tutorial/pk_bottom_up_parce.html

# 事前知識のグラフを描画する関数
def make_prior_knowledge_graph(prior_knowledge_matrix):
    d = graphviz.Digraph(engine='dot')

    labels = [f'x{i}' for i in range(prior_knowledge_matrix.shape[0])]
    for label in labels:
        d.node(label, label)

    dirs = np.where(prior_knowledge_matrix > 0)
    for to, from_ in zip(dirs[0], dirs[1]):
        d.edge(labels[from_], labels[to])

    dirs = np.where(prior_knowledge_matrix < 0)
    for to, from_ in zip(dirs[0], dirs[1]):
        if to != from_:
            d.edge(labels[from_], labels[to], style='dashed')
    return d

 

# 事前知識の隣接行列を作成
prior_knowledge = make_prior_knowledge(
    n_variables=5,
    sink_variables=[4],
)
print(prior_knowledge)

# 事前知識のグラフを描画
dot = make_prior_knowledge_graph(prior_knowledge)
dot.format = 'png'
dot.render('prior_knowledge')
dot
[[-1 -1 -1 -1  0]
 [-1 -1 -1 -1  0]
 [-1 -1 -1 -1  0]
 [-1 -1 -1 -1  0]
 [-1 -1 -1 -1 -1]]

 

# 標準化
scaler = StandardScaler()
Xy = scaler.fit_transform(dataset)

# モデル作成
model = lingam.BottomUpParceLiNGAM(random_state=1, prior_knowledge=prior_knowledge)
model.fit(Xy)

# 因果の順番
print(model.causal_order_)

# 隣接行列
print(model.adjacency_matrix_)
[[0, 1, 2, 3, 4]]
[[ 0. nan nan nan nan]
 [nan  0. nan nan nan]
 [nan nan  0. nan nan]
 [nan nan nan  0. nan]
 [nan nan nan nan  0.]]

 

dot = make_dot(model.adjacency_matrix_, labels=dataset.columns.to_list())
dot.format = 'png'
dot.render('BottomUpParceLiNGAM_with_prior_knowledge')
dot

事前知識あり

事前知識無し

今回の事前知識の仮定のもとでは、すべての変数ペアが未観測共通原因を持つモデルが推定されました。

 

CAM-UVで因果探索

CAM-UVでは、非線形かつ未観測共通原因を考慮して、因果探索を行えます。文献は以下です。

https://proceedings.mlr.press/v161/maeda21a.html

 

# 標準化
scaler = StandardScaler()
Xy = scaler.fit_transform(dataset)

# モデル作成
model = lingam.CAMUV()
model.fit(Xy)

# 隣接行列
print(model.adjacency_matrix_)
[[ 0.  0.  0.  1.  0.]
 [ 0.  0. nan  0.  0.]
 [ 0. nan  0.  1.  1.]
 [ 0.  1.  0.  0.  1.]
 [ 0.  0.  0.  0.  0.]]

 

# 因果グラフの描画
dot = make_dot(model.adjacency_matrix_, labels=dataset.columns.to_list())
dot.format = 'png'
dot.render('CAM-UV')
dot

コメント

タイトルとURLをコピーしました