Pythonの因果推論ライブラリ「DoWhy」でIrisデータセットを分析する
はじめに
久方ぶりに因果推論に取り組んでみようと思います。今回はPythonの因果推論ライブラリであるDoWhyを使用し、機械学習のサンプルとして有名なIris(アヤメ)データセットを題材に、因果効果の推定を実践してみます。
DoWhyは、因果推論のプロセスを「モデル化」「識別」「推定」「反証」の4つのステップに体系化しており、統一的なフレームワークで分析を行えるのが特徴です。
実装
コードはシンプルに記述します。
import sklearn
import pandas as pd
from dowhy import CausalModel
# データのロード
iris = sklearn.datasets.load_iris()
df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
df['target'] = iris.target
# 1. Model: 因果グラフの定義
# sepal length (がく片の長さ) が petal length (花弁の長さ) に与える影響を推定します。
# 交絡因子として sepal width (がく片の幅) と target (品種) を設定します。
model = CausalModel(
data=df,
treatment='sepal length (cm)',
outcome='petal length (cm)',
common_causes=['sepal width (cm)', 'target']
)
# 2. Identify: 因果効果の識別(推定対象の特定)
identified_estimand = model.identify_effect()
print(identified_estimand)
# 3. Estimate: 因果効果の推定
# バックドア基準に基づき、線形回帰を用いて推定します。
estimate = model.estimate_effect(identified_estimand, method_name="backdoor.linear_regression")
print(estimate)
推定結果の解釈
Irisデータセットにおいて、sepalは萼片(がくへん)、petalは花弁を表します。
今回は、「萼片の長さ(Treatment)」が「花弁の長さ(Outcome)」にどのような因果効果を持つかを推定しました。その際、品種(target)や萼片の幅(sepal width)が共通の要因(交絡因子)として働くと仮定しています。
得られた推定値(ATE: Average Treatment Effect)は以下の通りです。
Mean value: 0.8730017930766469
推定値は約 0.87 となりました。これは、「萼片の長さが1cm長くなると、花弁の長さは約0.87cm長くなる」という正の因果関係を示唆しています。花の構造的特徴として、全体的に大きい個体は各パーツも大きいという相関は自然であり、直感にも合う結果と言えます。
ちなみに、私は以前 LiNGAM を扱った経験がありますが、あちらは「因果探索(データから因果構造自体を発見する)」に重きを置いています。対してDoWhyは、ドメイン知識に基づいて因果グラフを仮定した上での「因果推論(効果の推定)」に強みがあります。
4. Refute: 推定結果の検証(反証)
因果推論において重要なのが、得られた結果の堅牢性を確認する「反証(Refutation)」のステップです。ここでは**プラセボテスト(Placebo Treatment Refuter)**を行います。
プラセボテストでは、本来の処置変数(Treatment)をランダムなノイズ(プラセボ)に置き換えて再推定を行います。もし因果関係が正しく捉えられていれば、ランダムなノイズが結果(Outcome)に与える影響はゼロに近づくはずです。
refutation = model.refute_estimate(identified_estimand, estimate, method_name="placebo_treatment_refuter")
print(refutation)
出力結果は以下の通りです。
Refute: Use a Placebo Treatment
Estimated effect:0.8730017930766469
New effect:-2.220446049250313e-15
p value:0.0
- Estimated effect: 元の推定値(0.873)
- New effect: プラセボを用いた場合の推定値(約 -2.22 × 10^-15 ≒ 0)
プラセボ変数の効果(New effect)はほぼゼロとなっており、期待通りの結果です。
なお、統計的検定の観点では、プラセボテストの p値は「効果が0である」という帰無仮説を棄却しないために、通常は 高い値(> 0.05) であることが望ましいとされます。
今回の結果では p value: 0.0 となっていますが、これはサンプルサイズや分散の影響で、極めて微小な値(10の-15乗オーダー)であっても統計的に「0ではない」と判定された可能性があります。しかし、効果量(New effect)自体が実質的にゼロであるため、実務的な解釈としては「プラセボによる不当な効果は観測されなかった(元の推定は妥当である)」と判断して良いでしょう。
モデルの可視化
最後に、定義した因果グラフ(DAG)を可視化してみます。
model.view_model()

まとめ
DoWhyを用いることで、因果推論のプロセスをコード上で明確に表現できました。特に refute_estimate による検証プロセスが手軽に実装できる点は、分析結果の信頼性を担保する上で非常に強力です。
Discussion