🎓 レベル:発展 | 重要度:C(発展的)
📎 前提:異質処置効果とメタ学習器(S/T/X-learner) | 識別の仮定 | 数理:バギングとランダムフォレスト(機械学習)
要点(BLUF)
- 因果フォレストは、決定木を「処置効果の異質性が最大になるように」分岐させ、葉ごとに CATE を推定する森。
- 鍵は honest splitting(正直な分割):木の分岐を決める標本と葉の中で効果を推定する標本を分け、過適合の偏りを抑えて信頼区間を出せるようにする。
- 段差状の真の を仕込み、
econmlのCausalForestDMLが RMSE 0.19 で段差を鋭く(1.0/3.0 を 1.01/3.02 と)回収し、素朴な RandomForest 近似(RMSE 0.74)を上回ることを確かめる。
因果フォレストの考え方
異質処置効果とメタ学習器(S/T/X-learner)の T-learner は「予測のための木」を 2 つ作って引き算した。これは予測誤差を小さくするよう分岐するので、効果の異質性とはズレた所で分かれてしまう。因果フォレストは最初から「効果 の違い」を狙って分岐する点が違う(Wager & Athey, 2018/一般化ランダムフォレスト grf)。
識別の仮定
例によって因果フォレストは推定の道具。識別の仮定の条件付き交換可能性・正値性・SUTVA が満たされて初めて、葉内の処置群・対照群の差が になる。未観測交絡があれば森を組んでも因果は出ない。
honest splitting(正直な分割)
flowchart LR
D["訓練データ"] --> S["標本A:木の分岐を決める(どこで分けるか)"]
D --> E["標本B:葉の中で効果を推定する"]
S --> TREE["honest tree"]
E --> TREE
TREE --> F["森:適応的な近傍重み αᵢ(x)"]
F --> TAU["τ̂(x) + 信頼区間"]
同じデータで「どこで分けるか」と「葉の効果」を両方決めると、たまたま効果が大きく出た方向に分岐してしまい、効果を過大評価する(選択バイアス)。honesty は両者を別標本に分けることでこれを断ち、葉内推定を(分岐構造を所与として)不偏にする。これが漸近正規性と妥当な信頼区間の根拠になる。
局所モーメントによる τ(x)
森は各訓練点 が点 と同じ葉に落ちる頻度を適応的な重み とみなし、局所的な残差回帰で を解く(交絡はDouble/Debiased Machine Learning(DML)と同じ残差化で除く)。
ここで は重み 付きの局所平均。木が近傍 をデータ駆動で決めるので、効果が変わる境界(ここでは )を自動で見つける。
コード:RandomForest による近似実装(必ず動く)
まず econml 不要の近似から。処置群・対照群に RandomForest を当てて引く T-learner で、段差をどこまで捉えられるか見る(正式な honest tree ではない点に注意)。
# === X0>0 で効果が段差状に増える擬似データを作り、RandomForest の T-learner で近似 ===
import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
from sklearn.ensemble import RandomForestRegressor
rng = np.random.default_rng(11)
n, p = 2000, 5
X = rng.standard_normal((n, p))
e = 1.0 / (1.0 + np.exp(-(0.7 * X[:, 0] + 0.7 * X[:, 1]))) # 傾向(交絡)
T = rng.binomial(1, e)
mu0 = 2 * X[:, 1] + X[:, 2]
tau_fn = lambda Z: 1.0 + 2.0 * (Z[:, 0] > 0) # 真のCATE: X0>0 で段差 +2
Y = mu0 + tau_fn(X) * T + rng.standard_normal(n)
forest_args = dict(n_estimators=300, min_samples_leaf=20, random_state=0)
rf1 = RandomForestRegressor(**forest_args).fit(X[T == 1], Y[T == 1])
rf0 = RandomForestRegressor(**forest_args).fit(X[T == 0], Y[T == 0])
rng_te = np.random.default_rng(222)
Xte = rng_te.standard_normal((4000, p))
tau_true = tau_fn(Xte)
tau_rf = rf1.predict(Xte) - rf0.predict(Xte)
print("RF T-learner RMSE :", round(np.sqrt(np.mean((tau_rf - tau_true) ** 2)), 3))
print(" X0<0 平均効果 :", round(tau_rf[Xte[:, 0] < 0].mean(), 3),
" / X0>0 平均効果 :", round(tau_rf[Xte[:, 0] > 0].mean(), 3), " (真値 1.0 と 3.0)")
grid = np.linspace(-2.5, 2.5, 100)
G = np.zeros((100, p)); G[:, 0] = grid
plt.figure(figsize=(8, 5))
plt.plot(grid, 1.0 + 2.0 * (grid > 0), "k--", lw=2, label="真の τ(x)")
plt.plot(grid, rf1.predict(G) - rf0.predict(G), label="RF T-learner 近似")
plt.xlabel("効果修飾子 X0"); plt.ylabel("推定処置効果 τ(x)")
plt.title("RandomForest T-learner による異質効果の近似")
plt.legend(); plt.tight_layout(); plt.show()
出力は次のとおり。
RF T-learner RMSE : 0.741
X0<0 平均効果 : 1.302 / X0>0 平均効果 : 2.912 (真値 1.0 と 3.0)
RF 近似は段差の方向は捉えるが、 付近でなまって、低い側を 1.30(真 1.0)と過大、高い側を 2.91(真 3.0)と過小に見積もる。各群を予測誤差最小で当てているため、境界がぼやけ、信頼区間も付かない。
コード:econml の CausalForestDML(要最新確認)
正式な honest splitting の因果フォレストは econml(v0.16.0 で確認)の CausalForestDML。API は要最新確認(未導入なら pip install econml)。X に効果修飾子、discrete_treatment=True で二値処置。
# === 同じデータに honest splitting の因果フォレストを当て、段差とCIを回収 ===
import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
from sklearn.ensemble import RandomForestRegressor
from econml.dml import CausalForestDML
rng = np.random.default_rng(11)
n, p = 2000, 5
X = rng.standard_normal((n, p))
e = 1.0 / (1.0 + np.exp(-(0.7 * X[:, 0] + 0.7 * X[:, 1])))
T = rng.binomial(1, e)
mu0 = 2 * X[:, 1] + X[:, 2]
Y = mu0 + (1.0 + 2.0 * (X[:, 0] > 0)) * T + rng.standard_normal(n)
cf = CausalForestDML(discrete_treatment=True, n_estimators=500, random_state=0)
cf.fit(Y, T, X=X, W=None)
rng_te = np.random.default_rng(222)
Xte = rng_te.standard_normal((4000, p))
tau_true = 1.0 + 2.0 * (Xte[:, 0] > 0)
tau_cf = cf.effect(Xte)
print("CausalForestDML RMSE :", round(np.sqrt(np.mean((tau_cf - tau_true) ** 2)), 3))
print(" X0<0 平均効果 :", round(tau_cf[Xte[:, 0] < 0].mean(), 3),
" / X0>0 平均効果 :", round(tau_cf[Xte[:, 0] > 0].mean(), 3), " (真値 1.0 と 3.0)")
grid = np.linspace(-2.5, 2.5, 100)
G = np.zeros((100, p)); G[:, 0] = grid
tau_grid = cf.effect(G)
lb, ub = cf.effect_interval(G, alpha=0.05)
rf1 = RandomForestRegressor(n_estimators=300, min_samples_leaf=20, random_state=0).fit(X[T == 1], Y[T == 1])
rf0 = RandomForestRegressor(n_estimators=300, min_samples_leaf=20, random_state=0).fit(X[T == 0], Y[T == 0])
plt.figure(figsize=(8, 5))
plt.plot(grid, 1.0 + 2.0 * (grid > 0), "k--", lw=2, label="真の τ(x)")
plt.plot(grid, rf1.predict(G) - rf0.predict(G), color="tab:orange", label="RF T-learner 近似")
plt.plot(grid, tau_grid, color="tab:green", label="CausalForestDML")
plt.fill_between(grid, lb, ub, color="tab:green", alpha=0.2, label="95%信頼区間")
plt.xlabel("効果修飾子 X0"); plt.ylabel("推定処置効果 τ(x)")
plt.title("因果フォレスト(honest splitting)による異質効果とCI")
plt.legend(); plt.tight_layout(); plt.show()
出力は次のとおり。
CausalForestDML RMSE : 0.191
X0<0 平均効果 : 1.006 / X0>0 平均効果 : 3.019 (真値 1.0 と 3.0)
RMSE 0.19 と RF 近似(0.74)の約 4 分の 1。 段差を 1.01/3.02 とほぼ正確に回収し、しかも各点の信頼区間(図の緑の帯)まで付く。honest splitting とDouble/Debiased Machine Learning(DML)の直交化により、境界が鋭く、推論も妥当になる。図では緑の階段が真の破線に重なり、橙の RF 近似だけが境界でなまる。
直観:いつ因果フォレストか
- 効果の異質性が滑らかでなく、相互作用が複雑なとき、木ベースは強い。線形 DML(Double/Debiased Machine Learning(DML))が苦手な段差・非線形の を捉える。
- 信頼区間が欲しいとき。honest splitting により点ごとの CI が出るので、「この層に本当に効いているか」を検定できる(メタ学習器単体では難しい)。
- どこに効くかで打ち手を変えたいとき。 で個体を並べ、効果の大きい層だけ介入するターゲティングに直結する。
- 正式実装は
econml/grf(R)。本ノートの RF T-learner は概念理解のための近似で、honesty も直交化も入っていない点に注意。
⚠️ よくある誤解・落とし穴
- honesty を省いた木は CATE を過大評価する。 同一標本で分岐と推定をすると、効果が大きく見えた所で分かれ、葉内推定が上振れる。RF T-learner 近似はまさに honesty が無いので境界がなまり、信頼区間も持てない。
- 識別が前提。 因果フォレストでも未観測交絡は救えない。 がバックドアを塞ぐという仮定(識別の仮定)が崩れれば、鋭い も偽物。
- 正値性の破れに弱い。 ある葉で処置群か対照群がほぼ居なければ局所推定が不安定。葉の最小サイズや傾向の重なりを点検する。
- 過剰な異質性探索。 効果修飾子の候補を無闇に増やすと、偶然の異質性を拾う。事前に意味のある修飾子へ絞り、別標本で再現を確認する。
econmlの API は要最新確認。X(修飾子)とW(交絡)の役割やdiscrete_treatmentの指定を取り違えると結果が変わる。近似ブロックで挙動を理解しておくと安全。
関連ノート
- 因果:異質処置効果とメタ学習器(S/T/X-learner)(S/T/X-learner)/Double/Debiased Machine Learning(DML)(直交化=CausalForestDML の D)/識別の仮定
- 機械学習:バギングとランダムフォレスト(森の土台)/決定木(木の分岐)/訓練・検証・テストと交差検証