Mímisbrunnr知恵の泉

← 因果推論 一覧

🎓 レベル:標準 | 重要度:A(必須) | ★ テキスト全体(全8章)の総まとめ

📎 前提:潜在結果モデル | 構造的因果モデルとdo演算子 | 因果推論のチェックリスト

要点(BLUF)


1. 相関 → 予測 → 因果の塔

Mímisbrunnr の 5 分野は 1 本の塔に積み上がる。下段が上段を支える。

flowchart TB
  L1["相関を測る(統計): cor(X,Y) は対称・向きを持たない"] --> L2["予測する(機械学習): P(Y∣X) 観測された X から Y を当てる"]
  L2 --> L3["介入の効果(因果推論): P(Y∣do(X)) X を設定したら Y はどうなるか"]

決定的な違いは 条件づけ(see)と介入(do)の差P(YX=x)P(Y\mid X{=}x) は「X=xX{=}x である人を見たときの YY」、P(Ydo(X=x))P(Y\mid do(X{=}x)) は「全員の XXxxしてみたときの YY」。交絡があると両者はずれる。

2. なぜ予測と介入で結論が逆になりうるか

具体例で見る。重症度 SS が交絡:重症の患者ほど (a) 積極治療 TT を受け、(b) もともと回復が悪い。だから観測データでは「積極治療を受けた人=重症者=回復が悪い」が見え、予測は「積極治療は回復に有害」と言う。だが治療そのものの効果は有益(真値 +8+8)。この反転を再現する。

flowchart LR
  S["交絡S: 重症度"] -->|"重症ほど治療を受ける"| T["処置T: 積極治療"]
  S -->|"重症ほど回復が悪い"| Y["結果Y: 回復スコア"]
  T -->|"真の効果 +8(有益)"| Y

真の介入効果 P(Ydo(T))P(Y\mid do(T)) は、交絡 SSバックドア調整して得る(バックドア基準と識別):

ATE=ES ⁣[E[YT=1,S]E[YT=0,S]]\mathrm{ATE} = E_S\!\big[\,E[Y\mid T{=}1, S] - E[Y\mid T{=}0, S]\,\big]

一方、予測の量 E[YT=1]E[YT=0]E[Y\mid T{=}1] - E[Y\mid T{=}0]SS を調整しない条件付きの差。両者を同じデータで比べる。

# === 同じデータで「予測(条件付き)」と「介入(do)」が逆の結論になる ===
import numpy as np
import statsmodels.api as sm

rng = np.random.default_rng(11)
n = 5000
ATE_true = 8.0     # 積極的治療の真の効果(回復スコアを+8する=本当は有益)

# 交絡:重症度 S(高いほど重症)。重症ほど積極治療を受け、かつ回復は悪い
severity = rng.normal(0, 1, n)
prob_care = 1 / (1 + np.exp(-(1.5 * severity)))         # 重症ほど積極治療を受けやすい
care = (rng.uniform(0, 1, n) < prob_care).astype(int)   # 処置T(1=積極治療)
recovery = 70 + ATE_true * care - 15 * severity + rng.normal(0, 5, n)  # 結果Y(高いほど良い)

# --- 予測の問い:P(Y | T) = 観測上、積極治療を受けた人の回復は? ---
pred_gap = recovery[care == 1].mean() - recovery[care == 0].mean()

# --- 介入の問い:P(Y | do(T)) = 重症度を揃えて治療を割り付けたら?(バックドア調整) ---
X = sm.add_constant(np.column_stack([care, severity]))
beta = sm.OLS(recovery, X).fit().params
do_effect = beta[1]    # 重症度を調整した治療の係数

print("ATE_true(真の介入効果)          :", ATE_true)
print("予測 P(Y|T=1)-P(Y|T=0)(条件付き):", round(pred_gap, 2))
print("介入 do調整後の効果(バックドア) :", round(do_effect, 2))
print("符号が逆:", "予測=" + ("負" if pred_gap < 0 else "正"),
      "/ 介入=" + ("正" if do_effect > 0 else "負"))

# --- Tは「予測子」としては有用(Yと相関)だが「介入対象」としては逆 ---
corr_TY = np.corrcoef(care, recovery)[0, 1]
print("相関 corr(T,Y)(予測子としての強さ):", round(corr_TY, 3))

出力:

ATE_true(真の介入効果)          : 8.0
予測 P(Y|T=1)-P(Y|T=0)(条件付き): -7.81
介入 do調整後の効果(バックドア) : 8.23
符号が逆: 予測=負 / 介入=正
相関 corr(T,Y)(予測子としての強さ): -0.275

出力の意味:真値は +8+8(治療は有益)。ところが 予測の差は 7.81-7.81——観測データだけ見ると「積極治療を受けた人ほど回復が悪い」。重症者が治療を受けるという交絡がそのまま符号を支配している。バックドア調整した介入効果は +8.23+8.23 で真値を回収し、符号は逆転して「治療は有益」になる。corr(T,Y)=-0.275 は、TTYY の予測子としては有効(相関がある)ことを示すが、その向きは介入の効果とは逆。「良い予測子」と「良い介入対象」は別物だ——ここを取り違えると、予測モデルを政策に直結して逆効果の意思決定をしてしまう。

図:交絡が予測と介入を食い違わせる

群ごとに見ると治療線(橙)は標準線(青)のにある(重症度を揃えれば治療は +8+8 有益)。だが橙の点は右(高重症度)に偏るため、周辺平均では橙が下に来る。同じ点群が、層の中では「治療が良い」、全体では「治療が悪い」と語る——相関と因果の違いのシンプソンの逆説そのものだ。

# === 図:交絡が予測と介入を食い違わせる様子を可視化 ===
import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib

rng = np.random.default_rng(11)
n = 5000
ATE_true = 8.0
severity = rng.normal(0, 1, n)
prob_care = 1 / (1 + np.exp(-(1.5 * severity)))
care = (rng.uniform(0, 1, n) < prob_care).astype(int)
recovery = 70 + ATE_true * care - 15 * severity + rng.normal(0, 5, n)

fig, ax = plt.subplots(figsize=(7, 5))
ax.scatter(severity[care == 0], recovery[care == 0], s=6, alpha=0.3, label="標準治療 T=0", color="tab:blue")
ax.scatter(severity[care == 1], recovery[care == 1], s=6, alpha=0.3, label="積極治療 T=1", color="tab:orange")

grid = np.linspace(severity.min(), severity.max(), 50)   # 群ごとの回帰線(重症度を揃えるとT=1が上)
for t, col in [(0, "tab:blue"), (1, "tab:orange")]:
    b1, b0 = np.polyfit(severity[care == t], recovery[care == t], 1)
    ax.plot(grid, b0 + b1 * grid, color=col, linewidth=2.5)

ax.axhline(recovery[care == 1].mean(), color="tab:orange", linestyle="--", alpha=0.7)  # 周辺平均
ax.axhline(recovery[care == 0].mean(), color="tab:blue", linestyle="--", alpha=0.7)
ax.set_xlabel("重症度 S(高いほど重症・交絡)")
ax.set_ylabel("回復スコア Y(高いほど良い)")
ax.set_title("予測は治療を「有害」、介入は「有益」と判断する(同じデータ)")
ax.legend(loc="upper right")
plt.tight_layout()
plt.show()

print("T=1の周辺平均:", round(recovery[care == 1].mean(), 2),
      " T=0の周辺平均:", round(recovery[care == 0].mean(), 2))

出力:

T=1の周辺平均: 70.13  T=0の周辺平均: 77.94

出力の意味:周辺平均は治療群 70.13 < 標準群 77.94 で、見かけ上「治療すると回復が低い」。だが図の橙の回帰線は青より一貫して上——層内の真の効果は逆。周辺(見かけ)と層内(因果)の符号が割れるのが交絡の怖さで、これが第1〜7章を貫く動機だった。

3. いつ予測で十分か、いつ介入が要るか

問いが「XX を動かさず、ただ YY を当てたい」なら P(YX)P(Y\mid X) =予測で十分で、交絡は問題にならない(むしろ予測子は何でも使ってよい)。問いが「XX を動かしたら YY がどう変わるか」なら P(Ydo(X))P(Y\mid do(X)) =因果が必要で、交絡の調整が要る。判断フローはこうなる。

flowchart TB
  START["問い:X を変えたら Y はどうなる?"] --> Q1{"X に介入する?(値を設定・政策判断)"}
  Q1 -->|"いいえ・予測だけ"| PRED["P(Y∣X) で十分。予測=機械学習(相関でよい)"]
  Q1 -->|"はい・介入する"| Q2{"無作為割付できる?"}
  Q2 -->|"はい"| RCT["RCT(第2章)で P(Y∣do(x)) を直接推定"]
  Q2 -->|"いいえ・観測データ"| Q3{"交絡をすべて観測できる?"}
  Q3 -->|"はい"| ADJ["バックドア調整(第3〜4章)"]
  Q3 -->|"いいえ"| Q4{"使える構造がある?(操作変数・断点・並行トレンド)"}
  Q4 -->|"はい"| QE["準実験デザイン(第5章)"]
  Q4 -->|"いいえ"| SENS["感度分析で頑健性を測る(第7章)"]

4. 全8章を貫く背骨——識別と推定の分離

このテキストの一貫した主張は 「識別(どんな仮定なら因果と言えるか)と推定(その効果をどう測るか)を必ず分ける」。全8章をこの背骨で振り返る。

テーマ識別(仮定)推定(測り方)
1枠組み潜在結果・交換可能性・正値性・SUTVA・バックドア(定義)
2RCT無作為化が交換可能性を設計的に保証平均差・ITT
3バックドア調整観測交絡で条件付き交換可能性回帰・傾向スコア・IPW・AIPW
4ML×因果同上(高次元交絡)DML(直交化+交差適合)
5準実験除外制約・並行トレンド・連続性など構造の仮定2SLS・DiD・RD・合成コントロール
6ベイズ・構造的因果do演算子・反事実・媒介の数学効果の事後分布・MCMC
7感度分析・落とし穴仮定が崩れたら結論はどれだけ動くかE-value・衝突点/過剰調整の回避
8応用・探索構造をデータから(同値類の限界)パイプライン・予測と因果の境界

識別の列が空白でない限り、推定の数字に因果の意味はない。第2章の無作為化、第3〜4章の観測交絡調整、第5章の構造的仮定、第6章の do の数学——どれも「何を仮定すれば P(Ydo(X))P(Y\mid do(X)) が観測分布で書けるか」を与える営みだった。推定(回帰・IPW・DML・MCMC)はその後の技術にすぎない。そして第7章で仮定が崩れたときの脆さを測り、第8章で構造そのものをデータから探り因果探索の概観)、問い→DAG→識別→推定→反証の一気通貫実データ事例と推定パイプライン)に結実する。

⚠️ よくある誤解・落とし穴

関連ノート