問いと設定
DAGは因果関係の仮説です。観測分布に対して含意する条件付き独立性があれば、その一部を検証できます。しかし棄却されなかったグラフが唯一の正解になるわけではありません。
今回はA→B、A→C、B→D、C→D、D→Eの線形ガウスSEMから3,000行を生成します。真のグラフ、マルコフ同値なグラフ、chain、逆向きの候補を比べます。生成式と乱数seedを固定し、元の下書きの表を転記せず再計算しました。
実行できるコード
Python 3.12.14で実行しました。解析はすべて合成データを使う研究・学習用の例です。
専用の仮想環境で、次の版をインストールして実行します。数値は2026-10-02の実行結果です。
python -m pip install numpy==2.4.6 pandas==3.0.6 scipy==1.15.3 scikit-learn==1.6.1 statsmodels==0.15.0 dowhy==0.14
次のコードは上から一括実行できます。seedを固定していますが、依存ライブラリや実装の変更で細かな数値は変わり得ます。
import numpy as np
import pandas as pd
import networkx as nx
from scipy.stats import t as student_t
from dowhy.gcm.falsify import falsify_graph
def partial_test(x,y,z=None):
x,y = np.asarray(x).reshape(-1),np.asarray(y).reshape(-1)
k = 0 if z is None else np.asarray(z).reshape(len(x),-1).shape[1]
design = np.ones((len(x),1)) if z is None else np.column_stack([np.ones(len(x)),np.asarray(z).reshape(len(x),-1)])
rx = x-design@np.linalg.lstsq(design,x,rcond=None)[0]
ry = y-design@np.linalg.lstsq(design,y,rcond=None)[0]
r = np.clip(np.corrcoef(rx,ry)[0,1],-.999999999999,.999999999999)
dof = len(x)-k-2
return float(2*student_t.sf(abs(r)*np.sqrt(dof/(1-r*r)),dof))
rng = np.random.default_rng(20261002)
n = 3000
a,eb,ec,ed,ee = rng.normal(size=(5,n))
b = .9*a+eb
c = -.7*a+ec
d = .8*b+.6*c+ed
e = 1.1*d+ee
df = pd.DataFrame(dict(A=a,B=b,C=c,D=d,E=e))
candidates = {
'true':[('A','B'),('A','C'),('B','D'),('C','D'),('D','E')],
'Markov equivalent':[('B','A'),('A','C'),('B','D'),('C','D'),('D','E')],
'chain':[('A','B'),('B','C'),('C','D'),('D','E')],
'wrong reverse':[('E','D'),('D','B'),('D','C'),('B','A')],
}
print('B independent C given A p:',partial_test(b,c,a))
print('A independent C given B p:',partial_test(a,c,b))
for name,edges in candidates.items():
np.random.seed(20261002)
result = falsify_graph(nx.DiGraph(edges),df,n_permutations=100,n_jobs=1,
independence_test=partial_test,conditional_independence_test=partial_test,
show_progress_bar=False)
print(name, result.falsifiable, result.falsified)
print(result)
実行結果
| 候補 | falsifiable | falsified | LMC違反数 | permutation LMC p |
|---|---|---|---|---|
| 真のDAG | True | False | 3/6 | 0.04 |
| マルコフ同値 | True | False | 3/5 | 0.04 |
| chain | True | True | 6/6 | 1.00 |
| 逆向き候補 | True | True | 8/8 | 1.00 |
直接確認したB ⟂ C | Aのp値は0.3563、chainが要求するA ⟂ C | Bのp値は約1.58×10⁻¹⁴²でした。後者は今回の生成過程と整合しません。
2種類のp値を混同しない
個々の独立性検定のp値と、表のpermutation LMC pは別の値です。falsify_graphは候補のLMC違反数を、ノードのラベルを並べ替えたグラフと比較します。表の小さいLMC pは「候補が多くの並べ替え候補より違反が少ない」ことを示し、通常の独立性検定のpと同じ向きで読んではいけません。tPaは、候補が検証に情報を持つかの基準です。
今回の真のグラフでも、個別LMCのうち3個が5%水準で違反と判定されました。有限標本での偽陽性、多重性、相関する検定があるため、真のグラフの違反数が常に0になるとは限りません。グラフ全体のpermutation基準では棄却されませんでした。違反した個別条件も確認し、判定フラグだけで済ませないことが必要です。
線形ガウスという検定側の前提
独立性の確認には、共変量で線形回帰した残差同士の相関を使いました。自由度はn−調整変数数−2です。今回の生成仮定では偏相関0と条件付き独立性が対応します。非線形・非ガウスのデータ一般で、偏相関が0なら独立という結論にはなりません。
マルコフ同値なDAGは同じ独立性を含意するため、この情報だけでは向きを確定できません。逆向きだから常に棄却できるという性質もありません。
実データでは、時点、未観測変数、測定誤差、選択、検定の適合性を確認し、候補グラフごとに効果の識別が変わるかを調べます。棄却されなかったという結果は、候補の因果的な正しさや未観測交絡の不在を証明するものではありません。