ある患者に新薬を投与したところ、病気が回復しました。この新薬は本当に効いたのでしょうか。「効いた」と結論するためには、仮にその患者に新薬を投与しなかった場合にどうなっていたか——つまり「もしも」の世界を知る必要があります。しかし、同じ患者について「新薬を飲んだ場合」と「飲まなかった場合」の両方を同時に観測することはできません。
この「もしも」の世界を数学的に扱う枠組みがポテンシャルアウトカム(potential outcomes)、あるいはルービン因果モデル(Rubin Causal Model, RCM)です。ドナルド・ルービン(Donald Rubin)によって1970年代に体系化されたこの枠組みは、因果推論の理論的基盤として現代の統計学・計量経済学・疫学で広く用いられています。
ポテンシャルアウトカムの枠組みを理解すると、以下のような場面で強力なツールとなります。
- 臨床試験の設計と解析: ランダム化比較試験(RCT)の統計的基盤を理解し、適切な検定やバイアス評価が可能になる
- 観察研究からの因果推定: 傾向スコア法、操作変数法、差の差法などの手法がなぜ機能するかを統一的に理解できる
- 政策評価: 教育プログラムや社会政策の効果を厳密に評価する枠組みを提供する
- 機械学習の因果的解釈: 予測モデルから因果モデルへの橋渡しとして、反事実推論の基盤となる
本記事では、ポテンシャルアウトカムの枠組みを基礎から構築します。反事実(counterfactual)の概念、SUTVA(Stable Unit Treatment Value Assumption)、因果推論の根本問題、そして無視可能性(ignorability)の仮定を順を追って解説し、Pythonシミュレーションを通じてこれらの概念を実感します。
本記事の内容
- 反事実と潜在結果の定義
- 因果推論の根本問題(観測の基本的限界)
- SUTVAの意味と重要性
- 平均処置効果(ATE)の定義と推定
- 無視可能性(強い意味での無視可能性)の仮定
- Pythonシミュレーションによる因果推論の根本問題の体験
前提知識
この記事を読む前に、以下の記事を読んでおくと理解が深まります。
反事実と潜在結果 — 「もしも」を数学にする
反事実とは何か
因果関係を考える上で避けて通れないのが反事実(counterfactual)の概念です。日常語では「もしあのとき違う選択をしていたら」という仮定法過去の文に相当します。
例えば、ある学生が塾に通って(処置 $T = 1$)テストで80点を取ったとします。このとき「塾の効果」を知るためには、「もしこの学生が塾に通わなかったら($T = 0$)何点だったか」を知る必要があります。しかし、この学生は実際には塾に通ったのですから、通わなかった場合のテストの点数は観測できない反事実です。
ルービンの枠組みでは、この「もしも」を潜在結果(potential outcomes)として数学的に定式化します。
潜在結果の定義
個体 $i$ に対して、処置変数 $T_i \in \{0, 1\}$($1$: 処置あり、$0$: 処置なし)を考えます。このとき、2つの潜在結果を定義します。
$$ \begin{equation} Y_i(1): \text{個体 } i \text{ が処置を受けた場合のアウトカム} \end{equation} $$
$$ \begin{equation} Y_i(0): \text{個体 } i \text{ が処置を受けなかった場合のアウトカム} \end{equation} $$
重要な点は、$Y_i(1)$ と $Y_i(0)$ はともに存在すると仮定することです。各個体には、処置を受けた場合と受けなかった場合の2つの「潜在的な」アウトカムが存在し、実際に観測されるのはそのうちの一方だけです。
実際に観測されるアウトカム $Y_i^{\text{obs}}$ は、処置の割り当てに応じて決まります。
$$ \begin{equation} Y_i^{\text{obs}} = T_i \cdot Y_i(1) + (1 – T_i) \cdot Y_i(0) \end{equation} $$
$T_i = 1$ ならば $Y_i^{\text{obs}} = Y_i(1)$ が観測され、$T_i = 0$ ならば $Y_i^{\text{obs}} = Y_i(0)$ が観測されます。
個体レベルの因果効果
個体 $i$ に対する個体処置効果(Individual Treatment Effect, ITE)は、2つの潜在結果の差として定義されます。
$$ \begin{equation} \tau_i = Y_i(1) – Y_i(0) \end{equation} $$
この定義は非常に直感的です。「処置を受けた場合のアウトカム」から「受けなかった場合のアウトカム」を引いた差が、その個体にとっての処置の効果です。塾の例で言えば、「塾に通ったら80点、通わなかったら65点」であれば、塾の効果は $\tau_i = 80 – 65 = 15$ 点です。
しかし、ここに根本的な困難があります。$Y_i(1)$ と $Y_i(0)$ の両方を同時に観測することは原理的に不可能なのです。この問題を次に詳しく見ていきましょう。
因果推論の根本問題
観測の基本的限界
前節で定義した個体処置効果 $\tau_i = Y_i(1) – Y_i(0)$ を計算するには、$Y_i(1)$ と $Y_i(0)$ の両方が必要です。しかし、式(3)からわかるように、各個体について実際に観測されるのは $Y_i(1)$ か $Y_i(0)$ のどちらか一方だけです。
| 個体 $i$ | $T_i$ | $Y_i(1)$ | $Y_i(0)$ | $\tau_i$ |
|---|---|---|---|---|
| 1 | 1 | 80 | ? | ? |
| 2 | 0 | ? | 65 | ? |
| 3 | 1 | 72 | ? | ? |
| 4 | 0 | ? | 70 | ? |
| 5 | 1 | 90 | ? | ? |
表の「?」が観測できない反事実(missing counterfactual)です。個体1は処置を受けたため $Y_1(1) = 80$ は観測されますが、$Y_1(0)$(処置を受けなかった場合のアウトカム)は永遠にわかりません。
この限界は、ポランド(Paul Holland)によって因果推論の根本問題(fundamental problem of causal inference)と名付けられました。これは統計学の問題ではなく、物理的な制約です。同じ個体が同じ時点で処置を受けると同時に受けないということはありえないからです。
なぜこれが「根本」問題なのか
この問題が根本的である理由を、もう少し掘り下げて考えてみましょう。
通常の統計学では、パラメータの推定が可能かどうかは識別可能性(identifiability)の問題として定式化されます。パラメータが識別可能であるとは、十分なデータがあれば原理的にパラメータの値を特定できるということです。
しかし、個体処置効果 $\tau_i$ の推定では、データ量を増やしても問題は解決しません。$n$ 個の個体を観測して $n \to \infty$ としても、各個体の欠損値(反事実)は埋まらないからです。これは通常の欠損データの問題とは根本的に異なります。通常の欠損データでは、欠損メカニズムに関する仮定のもとで欠損値を推定できますが、反事実の場合は同じ個体が2つの状態を経験することが論理的に不可能です。
個体から集団へ — 問題の回避
因果推論の根本問題への対処法は、個体レベルの因果効果を諦めて、集団レベルの因果効果を推定することです。集団内の個体間の異質性を利用して、「平均的にはどうか」という問いに答えます。
集団レベルで考えると、処置群の $Y_i(1)$ の平均と対照群の $Y_i(0)$ の平均は観測可能です。ある条件(無視可能性)のもとで、これらの観測量から集団レベルの因果効果を推定できます。
では、集団レベルの因果効果を議論する前に、潜在結果の枠組みが成り立つための基本的な仮定を確認しましょう。
SUTVA — 潜在結果を「ちゃんと定義する」ための仮定
SUTVAとは
SUTVA(Stable Unit Treatment Value Assumption、安定単位処置値仮定)は、ポテンシャルアウトカムの枠組みが意味を持つための基本的な仮定です。SUTVAは2つの条件から構成されます。
条件1: 干渉なし(no interference)
個体 $i$ の潜在結果 $Y_i(t)$ は、他の個体の処置の割り当てに依存しない。
$$ \begin{equation} Y_i(t) \text{ は } T_j \text{ に依存しない(} j \neq i \text{)} \end{equation} $$
直感的に言えば、「あなたがワクチンを接種するかどうかは、私の健康状態に影響しない」ということです。
条件2: 処置のバージョンの一意性(no hidden variations of treatments)
処置 $T = t$ の「やり方」は全個体で同じである。処置に隠れたバリエーションがない。
直感的に言えば、「新薬Aを投与する」と言ったとき、患者によって投与量が違ったり、異なるメーカーの薬が使われたりしないということです。
SUTVAが必要な理由
SUTVAがないと、潜在結果の定義自体が曖昧になります。もし個体 $i$ の潜在結果が他の個体の処置に依存するならば、$Y_i(1)$ という記法は不完全です。$Y_i(1)$ は「個体 $i$ が処置を受け、かつ他のすべての個体の処置割り当てがこうである場合の結果」と書かなければならず、潜在結果の数が爆発的に増えてしまいます。
$n$ 人の集団で各個体が $\{0, 1\}$ の処置を受ける場合、SUTVAなしでは各個体が $2^n$ 通りの潜在結果を持つことになり、推定は事実上不可能になります。SUTVAを仮定すると、各個体の潜在結果は $Y_i(0)$ と $Y_i(1)$ の2つだけに簡約化されます。
SUTVAが成り立たない例
SUTVAの重要性を理解するために、この仮定が成り立たない例を考えてみましょう。
ワクチンの集団免疫: あなたがワクチンを接種すると、あなただけでなく周囲の人の感染リスクも低下します。つまり、個体 $i$ のアウトカム(感染するかどうか)は、他の個体のワクチン接種状況に依存します。これは干渉なしの仮定に違反しています。
マーケティング: あなたの友人が広告を見てある製品を購入すると、口コミ効果であなたも購入する確率が高まるかもしれません。処置(広告の表示)の効果が個体間で伝播するため、SUTVAが成り立ちません。
教育: クラス全体に新しい教授法を適用すると、学生間の議論の質が変わり、個々の学生の学習効果がクラスメートの処置状況に依存します。
SUTVAが成り立たない場合には、ネットワーク上の因果推論など、より発展的な理論が必要になります。本記事では、SUTVAが成り立つ標準的な設定を前提として議論を進めます。
SUTVAの仮定のもとで潜在結果が明確に定義できるようになりました。次に、集団レベルの因果効果を正式に定義しましょう。
平均処置効果(ATE)の定義
ATEの定義
集団レベルで最も基本的な因果効果の指標が平均処置効果(Average Treatment Effect, ATE)です。
$$ \begin{equation} \text{ATE} = E[Y(1) – Y(0)] = E[Y(1)] – E[Y(0)] \end{equation} $$
ATEは、集団内のすべての個体の個体処置効果 $\tau_i = Y_i(1) – Y_i(0)$ の平均です。「もし集団全体に処置を施したら($T = 1$)、集団全体に施さなかった場合($T = 0$)と比べて、平均的にどれだけアウトカムが変わるか」を表します。
関連する因果効果の指標
ATEに加えて、以下のような因果効果の指標も重要です。
処置群の平均処置効果(ATT):
$$ \begin{equation} \text{ATT} = E[Y(1) – Y(0) \mid T = 1] \end{equation} $$
ATTは、「実際に処置を受けた人々にとっての処置の効果」を表します。処置群について、「もし処置を受けなかったら」との差を計算しています。政策評価では、ATEよりもATTの方が実用的に重要な場合が多いです。なぜなら、政策の対象者にとっての効果こそが意思決定に直結するからです。
対照群の平均処置効果(ATC):
$$ \begin{equation} \text{ATC} = E[Y(1) – Y(0) \mid T = 0] \end{equation} $$
ATCは、「処置を受けなかった人々が、もし処置を受けていたらどうなっていたか」を表します。
これら3つの指標の関係は次のようになります。
$$ \begin{equation} \text{ATE} = P(T = 1) \cdot \text{ATT} + P(T = 0) \cdot \text{ATC} \end{equation} $$
つまり、ATEはATTとATCの処置確率による加重平均です。処置効果が個体によって異質(heterogeneous)な場合、ATE、ATT、ATCは一般に異なる値を取ります。
ナイーブな推定量の問題
観測データからATEを「ナイーブに」推定しようとすると、処置群の平均アウトカムから対照群の平均アウトカムを引くことが自然に思えます。
$$ \hat{\tau}_{\text{naive}} = \bar{Y}_{\text{treated}} – \bar{Y}_{\text{control}} = E[Y^{\text{obs}} \mid T=1] – E[Y^{\text{obs}} \mid T=0] $$
しかし、これは一般にATEとは一致しません。なぜなら次のように分解できるからです。
$$ E[Y^{\text{obs}} \mid T=1] = E[Y(1) \mid T=1] $$
$$ E[Y^{\text{obs}} \mid T=0] = E[Y(0) \mid T=0] $$
したがって、ナイーブな推定量は次のようになります。
$$ \hat{\tau}_{\text{naive}} = E[Y(1) \mid T=1] – E[Y(0) \mid T=0] $$
ここで $E[Y(1)] – E[Y(0)]$ を得るには、$E[Y(1) \mid T=1] = E[Y(1)]$ かつ $E[Y(0) \mid T=0] = E[Y(0)]$ が成り立つ必要があります。つまり、潜在結果の期待値が処置の割り当てに依存しない、という条件が必要です。
ナイーブな推定量のバイアスをより詳細に分解すると、次のようになります。
$$ \hat{\tau}_{\text{naive}} – \text{ATE} = \underbrace{E[Y(0) \mid T=1] – E[Y(0) \mid T=0]}_{\text{選択バイアス}} + \underbrace{(1 – P(T=1))({\text{ATT} – \text{ATC}})}_{\text{効果の異質性バイアス}} $$
右辺第1項が選択バイアスです。処置群と対照群の「もともとの特性」($Y(0)$ で測る)が異なる場合に生じます。例えば、健康意識の高い人がワクチンを接種しやすく、もともと健康状態が良い($Y(0)$ が高い)ならば、選択バイアスが正の方向に生じます。
右辺第2項は効果の異質性に起因するバイアスです。処置効果が個体によって異なり、かつ処置を受けやすい人ほど効果が大きい(または小さい)場合に生じます。
これらのバイアスをゼロにするための十分条件が、次に述べる無視可能性の仮定です。
無視可能性 — 因果効果を識別するための鍵
強い意味での無視可能性
強い意味での無視可能性(strong ignorability)は、ローゼンバウムとルービン(Rosenbaum and Rubin, 1983)によって定式化された、観測データからATEを識別するための仮定です。2つの条件から構成されます。
条件1: 条件付き独立性(conditional independence / unconfoundedness)
共変量 $\bm{X}$ を条件付けたとき、潜在結果 $(Y(0), Y(1))$ と処置の割り当て $T$ が独立である。
$$ \begin{equation} (Y(0), Y(1)) \perp\!\!\!\perp T \mid \bm{X} \end{equation} $$
この条件は「条件付き交換可能性」(conditional exchangeability)や「選択の無視可能性」(selection on observables)とも呼ばれます。
直感的に言えば、共変量 $\bm{X}$ の値が同じ個体同士を比べれば、処置を受けた個体と受けなかった個体は「交換可能」(どちらが処置を受けてもおかしくない)であるということです。つまり、$\bm{X}$ を条件付けた後には、処置の割り当ては潜在結果に関する情報を持たない——言い換えれば、すべての交絡変数が $\bm{X}$ に含まれているということです。
条件2: 正値性(positivity / overlap)
すべての共変量の値について、処置を受ける確率が厳密に0でも1でもない。
$$ \begin{equation} 0 < P(T = 1 \mid \bm{X} = \bm{x}) < 1 \quad \text{for all } \bm{x} \end{equation} $$
この条件は、共変量のどの値に対しても処置群と対照群の両方が存在することを保証します。もし $P(T = 1 \mid \bm{X} = \bm{x}) = 1$ となる $\bm{x}$ が存在すると、その $\bm{x}$ のもとでは対照群が存在せず、$E[Y(0) \mid \bm{X} = \bm{x}]$ を推定できません。
無視可能性のもとでのATEの識別
強い意味での無視可能性が成り立つとき、ATEは観測データから次のように計算できます。条件付き独立性の仮定(10)から、次が成り立ちます。
$$ E[Y(1) \mid \bm{X}] = E[Y(1) \mid T=1, \bm{X}] = E[Y^{\text{obs}} \mid T=1, \bm{X}] $$
最初の等号は条件付き独立性から、2番目の等号は $T = 1$ のもとで観測されるのは $Y(1)$ であることからの帰結です。同様に次が成り立ちます。
$$ E[Y(0) \mid \bm{X}] = E[Y(0) \mid T=0, \bm{X}] = E[Y^{\text{obs}} \mid T=0, \bm{X}] $$
したがって、条件付き平均処置効果(CATE)は次のように観測量から表現できます。
$$ \begin{equation} \tau(\bm{x}) = E[Y^{\text{obs}} \mid T=1, \bm{X}=\bm{x}] – E[Y^{\text{obs}} \mid T=0, \bm{X}=\bm{x}] \end{equation} $$
ATEは、CATEを共変量の分布で周辺化することで得られます。
$$ \begin{equation} \text{ATE} = E[\tau(\bm{X})] = E\left[E[Y^{\text{obs}} \mid T=1, \bm{X}] – E[Y^{\text{obs}} \mid T=0, \bm{X}]\right] \end{equation} $$
この結果は、ATEが観測可能な量のみで表現できることを示しています。右辺の計算には、$\bm{X}$ の各値に対して処置群と対照群のアウトカム平均を比較し、それを $\bm{X}$ の分布で平均化するだけです。正値性の仮定(11)は、$\bm{X}$ のどの値でも両群の比較が可能であることを保証しています。
無視可能性の限界
無視可能性は強力な仮定ですが、大きな限界もあります。
検証不可能性: 条件付き独立性(10)は、観測データから検証することができません。なぜなら、$Y(0)$ と $Y(1)$ は同時に観測されないからです。この仮定が成り立っているかどうかは、因果的な知識やドメイン知識に基づいて判断するしかありません。
未観測の交絡: もし重要な交絡変数が $\bm{X}$ に含まれていなければ、条件付き独立性は成り立ちません。観測できない交絡変数(例: 個人の動機、遺伝的要因)が存在する場合、たとえすべての観測可能な変数を条件付けてもバイアスは残ります。
この限界に対処するために、操作変数法や感度分析など、無視可能性を緩和した手法が発展しています。
では、ここまでの理論をPythonシミュレーションで確認してみましょう。特に、因果推論の根本問題と無視可能性の仮定の役割を実感することを目指します。
Pythonシミュレーション — 因果推論の根本問題を体験する
シミュレーション1: 潜在結果の可視化
まず、「神の視点」でシミュレーションを行い、通常は見えない潜在結果の全体像を可視化します。シミュレーションでは$Y_i(0)$ と $Y_i(1)$ の両方をデータ生成過程として知ることができるため、個体処置効果 $\tau_i$ も直接計算できます。
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(42)
n = 500
# --- 潜在結果のデータ生成 ---
# 各個体の「能力」(観測されない個体差)
ability = np.random.normal(0, 1, n)
# 潜在結果
Y0 = 50 + 5 * ability + np.random.normal(0, 3, n) # 処置なし
Y1 = 55 + 7 * ability + np.random.normal(0, 3, n) # 処置あり
# 個体処置効果(神の視点)
ITE = Y1 - Y0
# 処置の割り当て(abilityが高いほど処置を受けやすい = 交絡)
prob_T = 1 / (1 + np.exp(-1.5 * ability))
T = np.random.binomial(1, prob_T, n)
# 観測されるアウトカム
Y_obs = T * Y1 + (1 - T) * Y0
print("=== 神の視点(シミュレーションでのみ可能)===")
print(f"真のATE: {np.mean(ITE):.4f}")
print(f"ATEの標準偏差: {np.std(ITE):.4f}")
print(f"ATTの真値: {np.mean(ITE[T==1]):.4f}")
print(f"ATCの真値: {np.mean(ITE[T==0]):.4f}")
print(f"\nナイーブ推定(処置群 - 対照群の観測平均): {Y_obs[T==1].mean() - Y_obs[T==0].mean():.4f}")
print(f"ナイーブ推定のバイアス: {(Y_obs[T==1].mean() - Y_obs[T==0].mean()) - np.mean(ITE):.4f}")
# --- 可視化 ---
fig, axes = plt.subplots(2, 2, figsize=(13, 10))
# (a) 潜在結果の散布図
ax = axes[0, 0]
ax.scatter(Y0[T==0], Y1[T==0], alpha=0.3, s=20, c="blue", label="Control (T=0)")
ax.scatter(Y0[T==1], Y1[T==1], alpha=0.3, s=20, c="red", label="Treated (T=1)")
lim = [min(Y0.min(), Y1.min()) - 2, max(Y0.max(), Y1.max()) + 2]
ax.plot(lim, lim, "k--", linewidth=1, label="Y(1)=Y(0)")
ax.set_xlabel("Y(0): potential outcome without treatment", fontsize=10)
ax.set_ylabel("Y(1): potential outcome with treatment", fontsize=10)
ax.set_title("(a) Potential outcomes (God's view)", fontsize=11)
ax.legend(fontsize=9)
ax.grid(True, alpha=0.3)
# (b) 個体処置効果の分布
ax = axes[0, 1]
ax.hist(ITE, bins=30, alpha=0.7, color="steelblue", edgecolor="black")
ax.axvline(np.mean(ITE), color="red", linewidth=2, linestyle="--",
label=f"ATE = {np.mean(ITE):.2f}")
ax.set_xlabel("Individual Treatment Effect (ITE)", fontsize=10)
ax.set_ylabel("Frequency", fontsize=10)
ax.set_title("(b) Distribution of ITE", fontsize=11)
ax.legend(fontsize=10)
ax.grid(True, alpha=0.3)
# (c) 観測データのみ(因果推論の根本問題)
ax = axes[1, 0]
ax.scatter(ability[T==0], Y_obs[T==0], alpha=0.4, s=20, c="blue",
label="Observed: Control")
ax.scatter(ability[T==1], Y_obs[T==1], alpha=0.4, s=20, c="red",
label="Observed: Treated")
# 欠損する反事実を薄く表示
ax.scatter(ability[T==0], Y1[T==0], alpha=0.08, s=10, c="red", marker="x")
ax.scatter(ability[T==1], Y0[T==1], alpha=0.08, s=10, c="blue", marker="x")
ax.set_xlabel("Ability (confounder)", fontsize=10)
ax.set_ylabel("Outcome Y", fontsize=10)
ax.set_title("(c) Observed data + missing counterfactuals (faded)",
fontsize=11)
ax.legend(fontsize=9)
ax.grid(True, alpha=0.3)
# (d) ナイーブ推定 vs 真のATEの比較
ax = axes[1, 1]
naive = Y_obs[T==1].mean() - Y_obs[T==0].mean()
true_ate = np.mean(ITE)
bars = ax.bar(["True ATE", "Naive estimate"],
[true_ate, naive],
color=["green", "red"], alpha=0.7, edgecolor="black")
ax.axhline(true_ate, color="green", linestyle="--", linewidth=1.5)
ax.set_ylabel("Effect estimate", fontsize=10)
ax.set_title("(d) True ATE vs Naive estimate", fontsize=11)
for bar, val in zip(bars, [true_ate, naive]):
ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.1,
f"{val:.2f}", ha="center", fontsize=11)
ax.grid(True, alpha=0.3, axis="y")
plt.tight_layout()
plt.savefig("potential_outcomes_fundamental.png", dpi=150, bbox_inches="tight")
plt.show()
この可視化から、以下の重要な点が読み取れます。
-
図(a): 各点は1人の個体を表し、横軸が $Y(0)$、縦軸が $Y(1)$ です。ほとんどの点が対角線($Y(1) = Y(0)$)の上側にあり、処置の効果が正であることを示しています。赤い点(処置群)が右上に偏っていることは、abilityが高い個体ほど処置を受けやすく、かつ両方の潜在結果が高い傾向にあることを反映しています。これが選択バイアスの視覚的な表現です
-
図(b): ITEの分布は正の値を中心に広がっており、処置効果に異質性があることがわかります。ATEは分布の平均であり、個々のITEは大きくばらついています
-
図(c): 実際に研究者が観測できるのは、各個体について青か赤の点のどちらか一方だけです。薄く表示されたバツ印が「見えない反事実」であり、これが因果推論の根本問題です。abilityが高い個体(右側)に赤い点(処置群)が集中していることが、交絡の存在を視覚的に示しています
-
図(d): ナイーブな推定値は真のATEよりも大きくなっています。これは正の選択バイアス(abilityが高い人ほど処置を受けやすく、かつアウトカムが高い)の帰結です
シミュレーション2: 無視可能性と交絡の制御
次に、無視可能性の仮定が満たされる場合に、共変量の条件付けにより因果効果が正しく推定できることを確認します。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
np.random.seed(42)
n = 5000
# --- データ生成 ---
X = np.random.normal(0, 1, n) # 観測可能な共変量
# 潜在結果
Y0 = 3 + 2 * X + np.random.normal(0, 1, n)
Y1 = 5 + 2 * X + np.random.normal(0, 1, n) # 真の因果効果 = 2.0
# 処置割り当て(Xに依存 = 交絡あり、しかしXは観測可能)
prob_T = 1 / (1 + np.exp(-2 * X))
T = np.random.binomial(1, prob_T, n)
# 観測アウトカム
Y_obs = T * Y1 + (1 - T) * Y0
# 真の因果効果
true_ATE = np.mean(Y1 - Y0)
# (a) ナイーブ推定
naive = Y_obs[T==1].mean() - Y_obs[T==0].mean()
# (b) 重回帰による推定(Xで条件付け)
reg = LinearRegression()
reg.fit(np.column_stack([T, X]), Y_obs)
adjusted = reg.coef_[0]
# (c) 層別推定(Xをビンに分けて条件付き効果を平均化)
n_bins = 20
X_bins = np.digitize(X, np.linspace(X.min(), X.max(), n_bins + 1))
cate_list = []
for b in range(1, n_bins + 1):
mask = X_bins == b
if T[mask].sum() > 5 and (~T[mask].astype(bool)).sum() > 5:
cate = Y_obs[mask & (T==1)].mean() - Y_obs[mask & (T==0)].mean()
cate_list.append(cate)
stratified = np.mean(cate_list)
print(f"真のATE: {true_ATE:.4f}")
print(f"ナイーブ推定: {naive:.4f} (バイアス: {naive - true_ATE:.4f})")
print(f"回帰による推定: {adjusted:.4f} (バイアス: {adjusted - true_ATE:.4f})")
print(f"層別推定: {stratified:.4f} (バイアス: {stratified - true_ATE:.4f})")
# --- 可視化 ---
fig, axes = plt.subplots(1, 2, figsize=(13, 5))
# (a) 推定結果の比較
ax = axes[0]
methods = ["True ATE", "Naive", "Regression\n(adjusted)", "Stratification"]
values = [true_ATE, naive, adjusted, stratified]
colors = ["green", "red", "blue", "purple"]
bars = ax.bar(methods, values, color=colors, alpha=0.7, edgecolor="black")
ax.axhline(true_ATE, color="green", linestyle="--", linewidth=1.5, alpha=0.7)
ax.set_ylabel("Estimated ATE", fontsize=12)
ax.set_title("Comparison of estimation methods", fontsize=12)
for bar, val in zip(bars, values):
ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.03,
f"{val:.3f}", ha="center", fontsize=10)
ax.grid(True, alpha=0.3, axis="y")
# (b) CATE(x)の推定
ax = axes[1]
x_grid = np.linspace(X.min(), X.max(), 50)
cate_estimated = []
for x_val in x_grid:
mask = np.abs(X - x_val) < 0.3
if T[mask].sum() > 3 and (~T[mask].astype(bool)).sum() > 3:
cate_estimated.append(Y_obs[mask & (T==1)].mean() - Y_obs[mask & (T==0)].mean())
else:
cate_estimated.append(np.nan)
ax.plot(x_grid, cate_estimated, "b-", linewidth=1.5, alpha=0.7, label="Estimated CATE")
ax.axhline(2.0, color="red", linestyle="--", linewidth=2, label="True CATE = 2.0")
ax.set_xlabel("Covariate X", fontsize=12)
ax.set_ylabel("CATE(x)", fontsize=12)
ax.set_title("Conditional Average Treatment Effect", fontsize=12)
ax.legend(fontsize=10)
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("potential_outcomes_ignorability.png", dpi=150, bbox_inches="tight")
plt.show()
このシミュレーション結果から、以下の重要な点が確認できます。
-
ナイーブ推定は大きくバイアスがかかっている。共変量 $X$ を無視した単純比較では、処置群にもともとアウトカムが高い個体($X$ が大きい個体)が多く含まれるため、因果効果を過大に推定してしまいます
-
重回帰と層別推定はどちらも真のATEに近い値を返している。これは、交絡変数 $X$ が観測されており、$X$ を条件付けることで無視可能性が満たされているためです。式(13)で示した理論的な結果が数値的に確認されています
-
CATE(x)は $x$ によらず概ね一定(約2.0)。これはデータ生成過程で $Y(1) – Y(0) = 2$ と設定したことと整合しています。CATE(x)が一定であることは、処置効果の異質性がないことを意味します。$X$ の端の値では推定の分散が大きくなっていますが、これはそれらの領域でサンプルサイズが小さいためです
シミュレーション3: ランダム化の効果
最後に、ランダム化比較試験(RCT)では処置の割り当てが潜在結果と独立であるため、無視可能性が無条件に成り立つことを確認します。
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(42)
n_trials = 1000
n_per_trial = 200
# 真のATE
true_ATE = 3.0
# --- RCT vs 観察研究のシミュレーション ---
rct_estimates = []
obs_estimates = []
for _ in range(n_trials):
# 交絡変数
Z = np.random.normal(0, 1, n_per_trial)
# 潜在結果
Y0 = 10 + 2 * Z + np.random.normal(0, 2, n_per_trial)
Y1 = Y0 + true_ATE + np.random.normal(0, 0.5, n_per_trial)
# RCT: ランダム割り当て(Zと独立)
T_rct = np.random.binomial(1, 0.5, n_per_trial)
Y_rct = T_rct * Y1 + (1 - T_rct) * Y0
rct_est = Y_rct[T_rct==1].mean() - Y_rct[T_rct==0].mean()
rct_estimates.append(rct_est)
# 観察研究: Zに依存した割り当て(交絡あり)
prob_obs = 1 / (1 + np.exp(-1.5 * Z))
T_obs = np.random.binomial(1, prob_obs, n_per_trial)
Y_obs = T_obs * Y1 + (1 - T_obs) * Y0
obs_est = Y_obs[T_obs==1].mean() - Y_obs[T_obs==0].mean()
obs_estimates.append(obs_est)
rct_estimates = np.array(rct_estimates)
obs_estimates = np.array(obs_estimates)
print("=== 1000回のシミュレーション結果 ===")
print(f"\n真のATE: {true_ATE:.2f}")
print(f"\nRCT推定の平均: {rct_estimates.mean():.4f}")
print(f"RCT推定の標準偏差: {rct_estimates.std():.4f}")
print(f"RCT推定のバイアス: {rct_estimates.mean() - true_ATE:.4f}")
print(f"\n観察研究推定の平均: {obs_estimates.mean():.4f}")
print(f"観察研究推定の標準偏差: {obs_estimates.std():.4f}")
print(f"観察研究推定のバイアス: {obs_estimates.mean() - true_ATE:.4f}")
# --- 可視化 ---
fig, axes = plt.subplots(1, 2, figsize=(13, 5))
# (a) 推定値のヒストグラム
ax = axes[0]
ax.hist(rct_estimates, bins=40, alpha=0.6, color="blue", label="RCT", density=True)
ax.hist(obs_estimates, bins=40, alpha=0.6, color="red", label="Observational", density=True)
ax.axvline(true_ATE, color="black", linewidth=2, linestyle="--", label=f"True ATE = {true_ATE}")
ax.axvline(rct_estimates.mean(), color="blue", linewidth=1.5, linestyle=":")
ax.axvline(obs_estimates.mean(), color="red", linewidth=1.5, linestyle=":")
ax.set_xlabel("Estimated ATE", fontsize=12)
ax.set_ylabel("Density", fontsize=12)
ax.set_title("Distribution of ATE estimates (1000 trials)", fontsize=12)
ax.legend(fontsize=10)
ax.grid(True, alpha=0.3)
# (b) バイアスの比較
ax = axes[1]
rct_bias = rct_estimates.mean() - true_ATE
obs_bias = obs_estimates.mean() - true_ATE
bars = ax.bar(["RCT", "Observational"],
[rct_bias, obs_bias],
color=["blue", "red"], alpha=0.7, edgecolor="black")
ax.axhline(0, color="black", linewidth=1)
ax.set_ylabel("Bias (estimate - true ATE)", fontsize=12)
ax.set_title("Bias comparison", fontsize=12)
for bar, val in zip(bars, [rct_bias, obs_bias]):
ax.text(bar.get_x() + bar.get_width()/2,
bar.get_height() + (0.02 if val >= 0 else -0.1),
f"{val:.4f}", ha="center", fontsize=11)
ax.grid(True, alpha=0.3, axis="y")
plt.tight_layout()
plt.savefig("potential_outcomes_rct_vs_obs.png", dpi=150, bbox_inches="tight")
plt.show()
このシミュレーションから、ランダム化の効果が明確に確認できます。
-
RCTの推定値(青)は真のATE = 3.0 を中心に対称に分布しています。バイアスはほぼゼロであり、推定のばらつき(標準偏差)のみが不確実性の源です。これは、ランダム化により $(Y(0), Y(1)) \perp\!\!\!\perp T$ が無条件に成り立つためです
-
観察研究の推定値(赤)は右にシフトしています。交絡変数 $Z$ が $T$ と $Y$ の両方に影響するため、処置群にはもともとアウトカムが高い個体が集まり、ナイーブな推定値は真のATEよりも大きくなります。この右シフトの量が選択バイアスです
-
RCTの推定値の分散は観察研究よりも大きい場合がある。これは、ランダム化がバイアスを除去する代わりに、有限サンプルでは偶然のインバランス(処置群と対照群で共変量の分布がわずかに異なる)が生じるためです。ただし、このインバランスは期待値的にはゼロであり、サンプルサイズを増やせば解消します
ポテンシャルアウトカム枠組みの歴史的意義と限界
歴史的意義
ポテンシャルアウトカムの概念自体は、実はルービン以前にネイマン(Jerzy Neyman)が1923年に農業実験の文脈で導入していました。ネイマンは完全ランダム化実験における分散の推定を議論する際に、各区画に対して「処置を受けた場合の収量」と「受けなかった場合の収量」という2つの量を定義しました。
ルービンの貢献は、この枠組みを観察研究にまで拡張し、無視可能性の仮定を明示化したことです。これにより、「どのような条件のもとで観測データから因果効果を推定できるか」という問いに対して、数学的に厳密な答えが得られるようになりました。
さらに、傾向スコア(propensity score)の概念をローゼンバウムとの共同研究(1983年)で導入し、高次元の共変量を1次元に要約して交絡を制御する方法を確立しました。
パールの枠組みとの関係
パールの構造因果モデル(SCM)とルービンのポテンシャルアウトカムの枠組みは、しばしば対立する立場として描かれますが、実際には相補的な関係にあります。
- ポテンシャルアウトカムの枠組みは、何を推定するか(ATEなどの因果量の定義)を明確にするのに優れています
- SCMとDAGは、いつ推定可能か(因果効果の識別条件の判定)に対して体系的な方法を提供します
多くの場面で、両方の枠組みを使い分けることが実践的です。
限界
ポテンシャルアウトカムの枠組みにはいくつかの限界があります。
- SUTVAの仮定が必要: ネットワーク効果や干渉が存在する場合、標準的な枠組みでは対処できません
- 処置が明確に定義されている必要がある: 「教育水準を上げる」のような曖昧な処置は、潜在結果の定義が困難です
- 個体処置効果は推定できない: 集団レベルの平均効果は推定できますが、特定の個体への効果は原理的にわかりません
- 因果構造の発見には向いていない: どの変数が原因でどの変数が結果かを発見するのではなく、因果関係が仮定されたもとでの効果の推定に特化しています
まとめ
本記事では、因果推論の理論的基盤であるポテンシャルアウトカム(ルービン因果モデル)の枠組みを解説しました。
- 潜在結果 $Y(0)$, $Y(1)$ は、処置を受けた場合と受けなかった場合のアウトカムであり、個体処置効果は $\tau_i = Y_i(1) – Y_i(0)$ で定義される
- 因果推論の根本問題: 各個体について潜在結果の片方しか観測できないため、個体処置効果を直接推定することは不可能である
- SUTVA(干渉なし+処置の一意性)は、潜在結果を明確に定義するための基本仮定である
- 平均処置効果(ATE) $= E[Y(1)] – E[Y(0)]$ は集団レベルの因果効果であり、根本問題を回避して推定の対象となる
- 強い意味での無視可能性(条件付き独立性+正値性)のもとで、ATEは観測データから識別可能になる
- ランダム化比較試験(RCT)は無視可能性を自動的に満たすが、観察研究ではすべての交絡変数を制御する必要がある
ポテンシャルアウトカムの枠組みは、因果効果の定義と推定の土台を提供します。この基盤の上に、傾向スコア法、操作変数法、差の差法などの具体的な推定手法が構築されていきます。
次のステップとして、以下の記事も参考にしてください。
- 平均処置効果(ATE)と条件付きATEの定義と推定 — ATEの推定方法を詳しく解説
- ランダム化比較試験(RCT) — 無視可能性を自動的に満たす実験デザイン
- 傾向スコア法 — 観察研究で無視可能性を活かす代表的な手法