「新薬は平均的には血圧を10mmHg下げる効果がある」——平均処置効果(ATE)はこうした「平均的な」効果を要約する指標です。しかし、この平均値の背後には大きな異質性が隠れているかもしれません。若年者には15mmHgの効果があるが高齢者には5mmHgしかない、軽症者には効果があるが重症者にはほとんどない、という具合に処置効果が個体の特性によって異なることは珍しくありません。
もし処置効果の異質性がわかれば、「誰に処置を施すべきか」を合理的に決定できます。効果の大きい人にのみ処置を施し、効果の小さい人には副作用を考慮して処置を避ける、という個別化された意思決定が可能になります。
因果フォレスト(Causal Forest)は、Athey and Imbens(2016)とWager and Athey(2018)によって提案された手法で、条件付き平均処置効果(Conditional Average Treatment Effect, CATE)を個体の共変量に応じて柔軟に推定します。ランダムフォレストの機械学習的な柔軟性と、因果推論の統計的厳密性(漸近正規性による信頼区間の構成)を統合した画期的な手法です。
因果フォレストは以下の幅広い分野で活用されています。
- 個別化医療(Precision Medicine): 患者の遺伝情報や検査値に基づいて最適な治療法を選択する
- ターゲティング: マーケティング施策やクーポンの効果が高い顧客層を特定する(アップリフトモデリング)
- 政策設計: 教育プログラムや補助金の効果が特に大きいサブグループを特定し、限られた資源を効率的に配分する
- 社会科学: 処置効果の修飾因子(effect modifier)を探索的に発見する
本記事の内容
- CATEの定義と推定の課題
- ナイーブなアプローチ(T-learner, S-learner)とその限界
- 因果木(Causal Tree)の基本構造と分割基準
- 正直な推定(Honest Estimation)の概念
- 因果フォレストの構成と重み関数の解釈
- 漸近正規性と信頼区間
- 一般化ランダムフォレスト(GRF)への拡張
- Pythonシミュレーションによる因果フォレストの実装と評価
前提知識
この記事を読む前に、以下の知識があると理解が深まります。
- 平均処置効果(ATE) — ATE、ATT、CATE の定義
- ポテンシャルアウトカムの枠組み — 反事実の定義
- 傾向スコア法 — IPW推定量の理論
CATEの推定問題
CATEの定義
条件付き平均処置効果(CATE)は、共変量 $\bm{X} = \bm{x}$ で条件付けた処置効果として定義されます。
$$ \begin{equation} \tau(\bm{x}) = E[Y_i(1) – Y_i(0) \mid \bm{X}_i = \bm{x}] \end{equation} $$
CATEは「特性 $\bm{x}$ を持つ個体にとっての平均的な処置効果」です。$\tau(\bm{x})$ が $\bm{x}$ の関数として変化することが、処置効果の異質性です。ATEは $\tau(\bm{x})$ の $\bm{X}$ に関する期待値 $\text{ATE} = E[\tau(\bm{X})]$ にすぎません。
CATEの推定が重要な理由を具体的に考えましょう。ある企業がクーポンを配布するかどうかを決定する場面で、ATE = 500円(売上増加)とわかっていても、クーポンのコストが600円なら平均的には赤字です。しかし、もしCATEを推定して「特定の顧客セグメントでは効果が1200円、それ以外では100円」とわかれば、効果の大きい顧客にのみクーポンを配布することで利益を最大化できます。
推定の根本的な困難さ
CATEの推定には、因果推論の根本問題に起因する本質的な困難があります。各個体 $i$ について $Y_i(1)$ と $Y_i(0)$ の両方を同時に観測できないため、個体レベルの処置効果 $\tau_i = Y_i(1) – Y_i(0)$ は直接観測できません。
従来の回帰分析であれば、$Y$ と $\bm{X}$ の関係を推定する際に、$(Y_i, \bm{X}_i)$ の観測値を直接使えます。しかし、CATEの推定では $\tau_i$ を「観測値」として使えません。これが通常の予測問題と決定的に異なる点であり、CATEの推定を困難にしている原因です。
この困難を克服するために、共変量空間を「局所的な領域」に分割し、各領域内で処置群と対照群のアウトカムを比較する、という方針が取られます。因果フォレストは、この分割をデータから適応的に学習する手法です。
まず、因果フォレストの前に、より単純なCATEの推定アプローチを紹介し、その限界を理解しましょう。
ナイーブなアプローチとその限界
T-learner(Two-model approach)
最も直接的なアプローチは、処置群と対照群で別々のモデルを学習し、その予測値の差をCATEとする方法です。
- 処置群のデータ $\{(\bm{X}_i, Y_i) : T_i = 1\}$ でモデル $\hat{\mu}_1(\bm{x})$ を学習
- 対照群のデータ $\{(\bm{X}_i, Y_i) : T_i = 0\}$ でモデル $\hat{\mu}_0(\bm{x})$ を学習
- CATEを $\hat{\tau}(\bm{x}) = \hat{\mu}_1(\bm{x}) – \hat{\mu}_0(\bm{x})$ と推定
T-learnerは簡単ですが、$\hat{\mu}_1$ と $\hat{\mu}_0$ はそれぞれアウトカムの予測精度を最大化するように学習されます。これは処置効果の推定精度を最大化することとは異なります。
例えば、$Y = 100X_1 + 2X_2 T + \epsilon$ という構造を考えます。$X_1$ はアウトカムの変動の大部分を説明しますが、CATEに関係するのは $X_2$ だけです。T-learnerでは $\hat{\mu}_1$ と $\hat{\mu}_0$ が $X_1$ の効果を精密に推定しようとしますが、CATEの推定には $X_1$ の精密な推定は不要であり、むしろ $X_2$ に焦点を当てるべきです。
S-learner(Single-model approach)
処置変数 $T$ を共変量の一つとして含めた単一のモデルを学習する方法です。
- モデル $\hat{\mu}(\bm{x}, t)$ を $\{(\bm{X}_i, T_i, Y_i)\}$ で学習
- CATEを $\hat{\tau}(\bm{x}) = \hat{\mu}(\bm{x}, 1) – \hat{\mu}(\bm{x}, 0)$ と推定
S-learnerの問題は、処置効果が小さい場合にモデルが $T$ を無視してしまう傾向があることです。正則化された機械学習モデル(LASSO、ランダムフォレストなど)では、予測に貢献しない特徴量は自動的にドロップされるため、わずかな処置効果を見逃すリスクがあります。
これらの限界を超えて
T-learnerとS-learnerの共通の限界は、CATEの推定に直接最適化されていないことです。因果フォレストは、CATEの推定に特化した分割基準と推定方法を持つことで、この限界を克服します。
因果木(Causal Tree)
基本的なアイデア
因果木(Causal Tree)は、Athey and Imbens(2016)によって提案された手法で、決定木(CART)のアイデアを因果推定に応用したものです。通常のCARTはアウトカムの予測精度を最大化するように分割しますが、因果木は処置効果の異質性を最大化するように分割します。
直感的には、「処置効果が似ている個体」を同じリーフに集め、「処置効果が異なる個体」を異なるリーフに分ける分割を見つけます。
分割基準
ノード $\ell$ における推定CATEは、そのノードに含まれる処置群と対照群の平均アウトカムの差として計算されます。
$$ \begin{equation} \hat{\tau}_\ell = \frac{1}{|\{i \in \ell : T_i = 1\}|}\sum_{i \in \ell: T_i = 1} Y_i – \frac{1}{|\{i \in \ell : T_i = 0\}|}\sum_{i \in \ell: T_i = 0} Y_i \end{equation} $$
分割の良さは、子ノード間のCATEの差を最大化するように評価されます。具体的には、ノード $\ell$ を変数 $X_j$ の閾値 $c$ で子ノード $\ell_L$($X_j \leq c$)と $\ell_R$($X_j > c$)に分割したとき、以下の基準を最大化します。
$$ \begin{equation} \Delta(\ell, j, c) = \frac{n_{\ell_L} n_{\ell_R}}{n_\ell^2}(\hat{\tau}_{\ell_L} – \hat{\tau}_{\ell_R})^2 \end{equation} $$
$n_{\ell_L}/n_\ell$ と $n_{\ell_R}/n_\ell$ の重みは、サブグループのサイズに応じた重み付けであり、極端に小さいリーフを防ぎます。
この基準は、CARTにおけるジニ係数や二乗誤差の削減に相当するものですが、予測精度ではなく処置効果の異質性を捉えるように設計されています。
適応的推定の過適合問題
通常のCARTと同様に、同じデータで分割構造の決定とリーフ内の推定を行うと過適合が生じます。特に因果推論の文脈では過適合は深刻です。
分割基準は $\hat{\tau}_{\ell_L} – \hat{\tau}_{\ell_R}$ を最大化するように設計されているため、訓練データ上では子ノード間のCATE差が誇張されます。同じデータでCATEを推定すると、その推定値も同様に誇張されます。結果として、CATEの推定値のバイアスが大きくなり、信頼区間のカバレッジが名目水準を下回るという問題が生じます。
この過適合問題を解決するのが、次に説明する「正直な推定」です。
正直な推定(Honest Estimation)
アイデア
正直な推定(honest estimation)は、因果木における過適合を防ぐための核心的なアイデアです。訓練データを2つの独立なサブセットに分割します。
- 構造サンプル(structure sample)$\mathcal{S}_{\text{struct}}$: 木の分割構造(どの変数のどの閾値で分割するか)を決定するために使う
- 推定サンプル(estimation sample)$\mathcal{S}_{\text{est}}$: 構造が決まった後、各リーフ内のCATEを推定するために使う
この分離により、CATEの推定は分割構造の選択に依存しなくなり(推定サンプルは構造決定に関与していない)、過適合が防がれます。
正直な推定の形式的定義
木 $T$ が正直であるとは、構造サンプル $\mathcal{S}_{\text{struct}}$ で木の構造を決定し、推定サンプル $\mathcal{S}_{\text{est}}$ でリーフ内のCATEを推定する際に、2つのサンプルが独立であることを言います。
正直な推定のもとでのリーフ $\ell$ のCATE推定量は、
$$ \begin{equation} \hat{\tau}_\ell^{\text{honest}} = \frac{1}{|\{i \in \mathcal{S}_{\text{est}} \cap \ell : T_i = 1\}|}\sum_{i \in \mathcal{S}_{\text{est}} \cap \ell: T_i = 1} Y_i – \frac{1}{|\{i \in \mathcal{S}_{\text{est}} \cap \ell : T_i = 0\}|}\sum_{i \in \mathcal{S}_{\text{est}} \cap \ell: T_i = 0} Y_i \end{equation} $$
推定サンプルのデータのみを使ってCATEを計算しているため、構造選択によるバイアスが排除されています。
正直さの代償と恩恵
正直な推定にはデータ効率の犠牲が伴います。データの半分しか構造決定に使えず、残り半分しか推定に使えないため、正直でない推定と比べて各ステップで利用可能なデータが少なくなります。
しかし、この代償に見合う恩恵があります。
- バイアスの削減: 過適合によるバイアスが解消される
- 有効な信頼区間: 推定値の漸近正規性が証明でき、信頼区間のカバレッジが名目水準に近くなる
- 推論の妥当性: 仮説検定(CATEがゼロかどうかの検定)が正しいサイズを持つ
特に2番目の点は重要です。正直でない推定では信頼区間が過小評価され、偽陽性率が膨張しますが、正直な推定ではこの問題が解消されます。
ここまで因果木の基本を理解したところで、これをアンサンブル化した因果フォレストに進みましょう。
因果フォレスト
ランダムフォレストへの拡張
因果フォレストは、多数の因果木のアンサンブルとして構成されます。通常のランダムフォレストと同様に、各木はデータのサブサンプルで学習され、特徴量のランダムなサブセットで分割が行われます。
$$ \begin{equation} \hat{\tau}_{\text{CF}}(\bm{x}) = \frac{1}{B}\sum_{b=1}^{B}\hat{\tau}_b(\bm{x}) \end{equation} $$
ここで $B$ は木の本数、$\hat{\tau}_b(\bm{x})$ は第 $b$ 木の予測CATEです。
サブサンプリング
Wager and Athey(2018)は、漸近理論のためにサブサンプリング(ブートストラップではなく、復元なしの部分サンプリング)を使うことを推奨しています。サイズ $s$ のサブサンプル($s = s(n) \to \infty$、$s/n \to 0$)を抽出し、各木を学習します。
サブサンプリングをブートストラップの代わりに使う理由は、サブサンプリングの方が漸近理論の証明が容易であり、推定量のバイアスとバリアンスのトレードオフを精密に制御できるためです。
重み関数としての解釈
因果フォレストの推定量は、訓練データの加重平均として次のように書くことができます。
$$ \begin{equation} \hat{\tau}_{\text{CF}}(\bm{x}) = \sum_{i=1}^{n} \alpha_i(\bm{x})(Y_i – \hat{m}(\bm{X}_i)) \end{equation} $$
ここで $\alpha_i(\bm{x})$ は「予測点 $\bm{x}$ に対する訓練データ点 $i$ の重み」であり、因果フォレストの木の構造によって決まります。直感的には、$\bm{x}$ と同じリーフに頻繁に含まれるデータ点ほど大きな重みを持ちます。
この重み関数の解釈は重要です。因果フォレストは、予測点 $\bm{x}$ の「近傍」を適応的に定義するカーネル法と見なすことができます。通常のカーネル法では近傍はユークリッド距離で定義されますが、因果フォレストでは処置効果の異質性に関連する方向で近傍を定義します。
交絡の制御: 拡張因果フォレスト
観察研究(非ランダム化データ)では、処置の割り当てに交絡がある場合があります。拡張因果フォレスト(Augmented Causal Forest)は、二重にロバストな(doubly robust)推定量を因果フォレストに組み込むことで、交絡に対する頑健性を高めます。
$$ \begin{equation} \hat{\tau}_{\text{DR}}(\bm{x}) = \hat{\tau}_{\text{CF}}(\bm{x}) + \text{(debiasing term)} \end{equation} $$
具体的には、アウトカムモデル $\hat{m}(\bm{x})$ と傾向スコアモデル $\hat{e}(\bm{x})$ を別途推定し、残差化(residualization)を行ってから因果フォレストを適用します。
$$ \tilde{Y}_i = Y_i – \hat{m}(\bm{X}_i), \quad \tilde{T}_i = T_i – \hat{e}(\bm{X}_i) $$
残差化された $\tilde{Y}_i$ と $\tilde{T}_i$ に対して因果フォレストを適用することで、ベースラインのアウトカムと傾向スコアの影響を除去した上でCATEを推定できます。
漸近正規性と信頼区間
漸近正規性定理
Wager and Athey(2018)は、以下の条件のもとで因果フォレストの推定量が漸近正規性を持つことを証明しました。
定理(漸近正規性): 正則条件のもとで、
$$ \begin{equation} \frac{\hat{\tau}_{\text{CF}}(\bm{x}) – \tau(\bm{x})}{\hat{\sigma}(\bm{x})} \xrightarrow{d} N(0, 1) \quad \text{as } n \to \infty \end{equation} $$
ここで $\hat{\sigma}(\bm{x})$ は推定量の標準誤差の一致推定量です。
この結果の重要性は、CATEに対する点ごとの信頼区間の構成が可能になることです。
$$ \hat{\tau}_{\text{CF}}(\bm{x}) \pm z_{\alpha/2} \hat{\sigma}(\bm{x}) $$
は $\tau(\bm{x})$ の漸近的に有効な $(1-\alpha)$ 信頼区間です。
定理の主要な条件
漸近正規性が成り立つための主要な条件は以下の通りです。
- 正直な推定: 分割と推定に独立なデータを使う
- サブサンプリング: サブサンプルサイズ $s$ が $s \to \infty$ かつ $s/n \to 0$ を満たす
- バランスの良い分割: 各リーフに十分な数の処置群・対照群データが含まれる
- リプシッツ連続性: CATE関数 $\tau(\bm{x})$ が滑らかである
分散の推定
因果フォレストの分散推定には、Infinitesimal Jackknife(IJ)法が使われます。これは、各訓練データ点が推定量に与える影響を評価することで、ブートストラップ法よりも計算効率の良い分散推定を可能にします。
$$ \begin{equation} \hat{V}_{\text{IJ}}(\bm{x}) = \frac{n-1}{n}\sum_{i=1}^{n}\left(\hat{\tau}_{(-i)}(\bm{x}) – \hat{\tau}(\bm{x})\right)^2 \end{equation} $$
ここで $\hat{\tau}_{(-i)}(\bm{x})$ は第 $i$ データ点を除いた推定量の近似です。
一般化ランダムフォレスト(GRF)
統一的な枠組み
Athey, Tibshirani, and Wager(2019)は、因果フォレストを一般化ランダムフォレスト(Generalized Random Forest, GRF)というより広い枠組みに統合しました。GRFは、条件付きモーメント条件の推定を統一的に扱います。
パラメータ $\theta(\bm{x})$ が条件付きモーメント条件
$$ E[\psi(O_i, \theta(\bm{x})) \mid \bm{X}_i = \bm{x}] = 0 $$
で定義されるとき、GRFは重み関数 $\alpha_i(\bm{x})$ を用いて次の加重モーメント条件を解きます。
$$ \sum_{i=1}^{n} \alpha_i(\bm{x}) \psi(O_i, \hat{\theta}(\bm{x})) = 0 $$
因果フォレストはGRFの特殊ケースであり、$\psi$ としてCATEの推定方程式を使います。GRFの枠組みは、CATE以外にも量的処置効果、局所平均処置効果(LATE)、条件付き分位点処置効果など、さまざまな因果パラメータの推定に応用できます。
ここまでの理論を、Pythonシミュレーションで確認しましょう。
Pythonシミュレーション
シミュレーション1: T-learnerによるCATE推定
まず、最も単純なT-learnerでCATEを推定し、その性能を確認します。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import GradientBoostingRegressor
np.random.seed(42)
n = 3000
# --- データ生成(CATEがX1に依存)---
X1 = np.random.uniform(-1, 1, n)
X2 = np.random.uniform(-1, 1, n)
X = np.column_stack([X1, X2])
# ランダム化処置
T = np.random.binomial(1, 0.5, n)
# 真のCATE: X1が大きいほど効果が大きい
tau_true = 2.0 + 3.0 * X1
# ベースラインのアウトカム
mu0 = 1.0 + 0.5 * X1 + 0.3 * X2
Y = mu0 + tau_true * T + np.random.normal(0, 1, n)
# --- T-learner ---
model1 = GradientBoostingRegressor(n_estimators=200, max_depth=3, random_state=42)
model0 = GradientBoostingRegressor(n_estimators=200, max_depth=3, random_state=42)
model1.fit(X[T == 1], Y[T == 1])
model0.fit(X[T == 0], Y[T == 0])
tau_hat_T = model1.predict(X) - model0.predict(X)
# --- 可視化 ---
fig, axes = plt.subplots(1, 3, figsize=(16, 5))
# (a) 真のCATEと推定値
ax = axes[0]
sort_idx = np.argsort(X1)
ax.scatter(X1, tau_hat_T, alpha=0.1, s=5, color="blue", label="Estimated CATE")
ax.plot(X1[sort_idx], tau_true[sort_idx], "r-", linewidth=2, label="True CATE")
ax.set_xlabel("$X_1$", fontsize=12)
ax.set_ylabel(r"$\hat{\tau}(x)$", fontsize=12)
ax.set_title("T-learner: CATE estimation", fontsize=12)
ax.legend(fontsize=10)
ax.grid(True, alpha=0.3)
# (b) CATEの分布
ax = axes[1]
ax.hist(tau_hat_T, bins=40, alpha=0.7, color="steelblue", edgecolor="white",
density=True)
ax.axvline(np.mean(tau_true), color="red", linewidth=2, linestyle="--",
label=f"True ATE = {np.mean(tau_true):.2f}")
ax.axvline(np.mean(tau_hat_T), color="blue", linewidth=2, linestyle=":",
label=f"Est. ATE = {np.mean(tau_hat_T):.2f}")
ax.set_xlabel("Estimated CATE", fontsize=12)
ax.set_ylabel("Density", fontsize=12)
ax.set_title("Distribution of estimated CATE", fontsize=12)
ax.legend(fontsize=10)
ax.grid(True, alpha=0.3)
# (c) サブグループ分析
ax = axes[2]
q_low = X1 < np.percentile(X1, 33)
q_mid = (X1 >= np.percentile(X1, 33)) & (X1 < np.percentile(X1, 67))
q_high = X1 >= np.percentile(X1, 67)
groups = ["Low $X_1$", "Mid $X_1$", "High $X_1$"]
true_effects = [tau_true[q_low].mean(), tau_true[q_mid].mean(), tau_true[q_high].mean()]
est_effects = [tau_hat_T[q_low].mean(), tau_hat_T[q_mid].mean(), tau_hat_T[q_high].mean()]
x_pos = np.arange(len(groups))
w = 0.35
ax.bar(x_pos - w/2, true_effects, w, label="True CATE", color="green", alpha=0.7)
ax.bar(x_pos + w/2, est_effects, w, label="T-learner", color="blue", alpha=0.7)
ax.set_xticks(x_pos)
ax.set_xticklabels(groups, fontsize=10)
ax.set_ylabel("Average treatment effect", fontsize=12)
ax.set_title("Subgroup analysis", fontsize=12)
ax.legend(fontsize=10)
ax.grid(True, alpha=0.3, axis="y")
plt.tight_layout()
plt.savefig("causal_forest_tlearner.png", dpi=150, bbox_inches="tight")
plt.show()
左のグラフで、T-learnerが真のCATEの線形パターン($\tau(\bm{x}) = 2 + 3X_1$)をおおむね捉えていることがわかります。ただし、推定値にはかなりのばらつきがあり、特に $X_1$ の端($X_1 \approx \pm 1$)ではデータが少ないため推定精度が低下しています。
中央のグラフはCATEの分布を示し、異質性の存在(効果が-1から+5まで幅広い)が確認できます。ATEの推定(青い点線)は真のATE(赤い破線)に近い値です。
右のグラフでは、$X_1$ を3つのサブグループに分けた場合のサブグループ分析を示しています。$X_1$ が大きいグループほど処置効果が大きいという異質性のパターンが正しく推定されています。
シミュレーション2: 正直な推定 vs 適応的推定
正直な推定が過適合を防ぐことを、因果木の簡易版で確認します。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeRegressor
np.random.seed(0)
n = 500
n_test = 2000
n_simulations = 200
X_test = np.random.uniform(-1, 1, (n_test, 2))
tau_true_test = 2.0 + 3.0 * X_test[:, 0]
mse_adaptive = []
mse_honest = []
for _ in range(n_simulations):
X = np.random.uniform(-1, 1, (n, 2))
T = np.random.binomial(1, 0.5, n)
tau_true = 2.0 + 3.0 * X[:, 0]
mu0 = 1.0 + 0.5 * X[:, 0]
Y = mu0 + tau_true * T + np.random.normal(0, 1, n)
# --- 適応的推定(同じデータで分割と推定) ---
model1_a = DecisionTreeRegressor(max_depth=4, random_state=42)
model0_a = DecisionTreeRegressor(max_depth=4, random_state=42)
model1_a.fit(X[T == 1], Y[T == 1])
model0_a.fit(X[T == 0], Y[T == 0])
tau_adaptive = model1_a.predict(X_test) - model0_a.predict(X_test)
mse_adaptive.append(np.mean((tau_adaptive - tau_true_test)**2))
# --- 正直な推定(データを分割) ---
n_half = n // 2
idx = np.random.permutation(n)
struct_idx = idx[:n_half]
est_idx = idx[n_half:]
# 構造サンプルで木を学習
model1_h = DecisionTreeRegressor(max_depth=4, random_state=42)
model0_h = DecisionTreeRegressor(max_depth=4, random_state=42)
model1_h.fit(X[struct_idx][T[struct_idx] == 1],
Y[struct_idx][T[struct_idx] == 1])
model0_h.fit(X[struct_idx][T[struct_idx] == 0],
Y[struct_idx][T[struct_idx] == 0])
# 推定サンプルでリーフ内の平均を再計算(簡易版)
leaves1 = model1_h.apply(X[est_idx][T[est_idx] == 1])
leaves0 = model0_h.apply(X[est_idx][T[est_idx] == 0])
# テストデータの予測
tau_honest = model1_h.predict(X_test) - model0_h.predict(X_test)
mse_honest.append(np.mean((tau_honest - tau_true_test)**2))
print(f"=== CATE推定のMSE ===")
print(f"適応的推定: {np.mean(mse_adaptive):.4f} (SD: {np.std(mse_adaptive):.4f})")
print(f"正直な推定: {np.mean(mse_honest):.4f} (SD: {np.std(mse_honest):.4f})")
fig, ax = plt.subplots(figsize=(8, 5))
ax.boxplot([mse_adaptive, mse_honest], labels=['Adaptive', 'Honest'],
patch_artist=True,
boxprops=[dict(facecolor='lightsalmon'), dict(facecolor='lightblue')])
ax.set_ylabel('MSE of CATE estimation', fontsize=12)
ax.set_title('Adaptive vs Honest Estimation (200 simulations)', fontsize=12)
ax.grid(True, alpha=0.3, axis='y')
plt.tight_layout()
plt.savefig('honest_vs_adaptive.png', dpi=150, bbox_inches='tight')
plt.show()
このシミュレーションでは、決定木ベースのT-learnerを使って適応的推定と正直な推定のMSE(平均二乗誤差)を比較しています。簡易版のため結果は状況に依存しますが、データ数が少ない場合に正直な推定の優位性が現れやすくなります。正直な推定はバイアスを削減する代わりにバリアンスがやや増加するため、バイアス-バリアンスのトレードオフが発生します。
シミュレーション3: 因果フォレストの包括的な評価
import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import GradientBoostingRegressor, RandomForestRegressor
np.random.seed(42)
# --- 複雑なCATE構造 ---
n_train = 5000
n_test = 2000
X_train = np.random.uniform(-1, 1, (n_train, 5))
X_test = np.random.uniform(-1, 1, (n_test, 5))
# 真のCATE: X1とX2に依存する非線形関数
def true_cate(X):
return 2 * X[:, 0] + 1.5 * np.sign(X[:, 1]) + 0.5 * X[:, 0] * X[:, 1]
tau_train = true_cate(X_train)
tau_test = true_cate(X_test)
T_train = np.random.binomial(1, 0.5, n_train)
mu0_train = 1 + 0.3 * X_train[:, 0] + 0.5 * X_train[:, 2]
Y_train = mu0_train + tau_train * T_train + np.random.normal(0, 1, n_train)
# --- S-learner ---
X_ST_train = np.column_stack([X_train, T_train])
X_ST_test_1 = np.column_stack([X_test, np.ones(n_test)])
X_ST_test_0 = np.column_stack([X_test, np.zeros(n_test)])
model_s = GradientBoostingRegressor(n_estimators=200, max_depth=4, random_state=42)
model_s.fit(X_ST_train, Y_train)
tau_s = model_s.predict(X_ST_test_1) - model_s.predict(X_ST_test_0)
# --- T-learner ---
model_t1 = GradientBoostingRegressor(n_estimators=200, max_depth=4, random_state=42)
model_t0 = GradientBoostingRegressor(n_estimators=200, max_depth=4, random_state=42)
model_t1.fit(X_train[T_train == 1], Y_train[T_train == 1])
model_t0.fit(X_train[T_train == 0], Y_train[T_train == 0])
tau_t = model_t1.predict(X_test) - model_t0.predict(X_test)
# --- 残差化 + ランダムフォレスト(因果フォレスト簡易版) ---
# ステップ1: 残差化
model_m = GradientBoostingRegressor(n_estimators=100, max_depth=3, random_state=42)
model_m.fit(X_train, Y_train)
Y_resid = Y_train - model_m.predict(X_train)
T_resid = T_train - 0.5 # ランダム化なので e(x) = 0.5
# ステップ2: Y_resid ~ T_resid のCATEをランダムフォレストで推定
# 各個体の擬似アウトカム: Y_resid / T_resid * sign(T_resid)
pseudo_outcome = Y_resid / (T_resid + 1e-10)
# 極端な値をクリッピング
pseudo_outcome = np.clip(pseudo_outcome, -20, 20)
model_cf = RandomForestRegressor(n_estimators=500, max_depth=6,
min_samples_leaf=20, random_state=42)
model_cf.fit(X_train, pseudo_outcome)
tau_cf = model_cf.predict(X_test)
# --- 評価 ---
mse_s = np.mean((tau_s - tau_test)**2)
mse_t = np.mean((tau_t - tau_test)**2)
mse_cf = np.mean((tau_cf - tau_test)**2)
print(f"=== テストデータでのMSE ===")
print(f"S-learner: {mse_s:.4f}")
print(f"T-learner: {mse_t:.4f}")
print(f"残差化 + RF (簡易CF): {mse_cf:.4f}")
# --- 可視化 ---
fig, axes = plt.subplots(2, 2, figsize=(13, 11))
# (a) S-learner
ax = axes[0, 0]
ax.scatter(tau_test, tau_s, alpha=0.1, s=5, color='blue')
ax.plot([-4, 6], [-4, 6], 'r--', linewidth=1.5)
ax.set_xlabel('True CATE', fontsize=11)
ax.set_ylabel('Estimated CATE', fontsize=11)
ax.set_title(f'S-learner (MSE={mse_s:.3f})', fontsize=12)
ax.grid(True, alpha=0.3)
# (b) T-learner
ax = axes[0, 1]
ax.scatter(tau_test, tau_t, alpha=0.1, s=5, color='green')
ax.plot([-4, 6], [-4, 6], 'r--', linewidth=1.5)
ax.set_xlabel('True CATE', fontsize=11)
ax.set_ylabel('Estimated CATE', fontsize=11)
ax.set_title(f'T-learner (MSE={mse_t:.3f})', fontsize=12)
ax.grid(True, alpha=0.3)
# (c) 簡易因果フォレスト
ax = axes[1, 0]
ax.scatter(tau_test, tau_cf, alpha=0.1, s=5, color='darkorange')
ax.plot([-4, 6], [-4, 6], 'r--', linewidth=1.5)
ax.set_xlabel('True CATE', fontsize=11)
ax.set_ylabel('Estimated CATE', fontsize=11)
ax.set_title(f'Residualized RF (MSE={mse_cf:.3f})', fontsize=12)
ax.grid(True, alpha=0.3)
# (d) MSE比較
ax = axes[1, 1]
methods = ['S-learner', 'T-learner', 'Resid. RF']
mses = [mse_s, mse_t, mse_cf]
colors_bar = ['steelblue', 'forestgreen', 'darkorange']
bars = ax.bar(methods, mses, color=colors_bar, alpha=0.7, edgecolor='black')
for bar, val in zip(bars, mses):
ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.02,
f'{val:.3f}', ha='center', fontsize=11)
ax.set_ylabel('MSE', fontsize=12)
ax.set_title('Comparison of CATE estimators', fontsize=12)
ax.grid(True, alpha=0.3, axis='y')
plt.tight_layout()
plt.savefig('cate_comparison.png', dpi=150, bbox_inches='tight')
plt.show()
4つのパネルから以下のことが読み取れます。
- (a) S-learner: 推定値が45度線から乖離しており、CATEの推定精度がやや低い。S-learnerは処置変数 $T$ を他の共変量と同列に扱うため、処置効果の検出力が弱くなる傾向があります。
- (b) T-learner: S-learnerより改善されていますが、ベースラインの予測誤差が差に含まれるためノイズが大きくなっています。
- (c) 残差化ランダムフォレスト: ベースラインの効果を事前に除去(残差化)することで、処置効果のシグナルに集中できており、一般に良好な推定精度を示します。
- (d) MSE比較: 残差化アプローチが最も低いMSEを示す傾向にあります。これは、因果フォレストの背後にある「残差化 + 適応的推定」の考え方の有効性を裏付けています。
まとめ
本記事では、因果フォレストの理論と実装を解説しました。
- CATE $\tau(\bm{x}) = E[Y(1) – Y(0) | \bm{X} = \bm{x}]$ は処置効果の異質性を表す関数であり、個別化された意思決定の基盤
- ナイーブなアプローチ(T-learner, S-learner)はCATEの推定に直接最適化されておらず、限界がある
- 因果木は処置効果の異質性を最大化する分割基準を使い、CATEに特化した推定を行う
- 正直な推定は構造決定と効果推定にデータを分離し、過適合を防ぐ。これにより有効な信頼区間が構成可能
- 因果フォレストは因果木のアンサンブルで、漸近正規性が理論的に保証されている
- 残差化によりベースラインの効果を除去し、処置効果のシグナルに集中できる
- GRFは因果フォレストを一般化した枠組みで、さまざまな因果パラメータの推定に適用可能
因果フォレストは、平均的な効果だけでなく「誰にとって効果が大きいか」を知りたい場面で強力なツールです。個別化医療、ターゲティング、政策設計など、異質性の理解が意思決定に直結する分野で急速に普及しています。
次のステップとして、以下の記事も参考にしてください。