Pythonで因果推論(2)~反実仮想と因果効果~
はじめに
反実仮想や平均処置効果(ATE)をはじめとした様々な因果効果の考え方は、「施策が、ある変数に与える影響を推定する」因果推論において非常に重要です。そのような反実仮想や因果効果について、Pythonによる実装を交えてまとめました。内容について誤り等がありましたら、コメントにてご指摘いただけますと幸いです。
疑似データの作成
本記事で紹介する用語や指標の具体例として利用するため、「特講の受講と試験の得点」という疑似データを自作します。
設定
とある大学の経済学部生60人を対象に、夏季休暇期間に計量経済学の特別講義(特講)を開催し、その効果を考えます。特講は、あくまでも大学の単位とは無関係の任意参加であるため、介入操作が行われない限りは受講するかどうかは学生の意欲に依存すると考えます。夏季休暇終了後に、特講の受講にかかわらず対象者60人に対して計量経済学の試験を実施し、その得点のデータを観測します。
説明変数
- 学習意欲
: 一様分布(0, 100)に従うX - 特講の受講
: 学習意欲D に依存するX -
であれば、X + noise \leq 50 (受講しない)D = 0 -
であれば、X + noise > 50 (受講する)D = 1 -
は、一様分布(-20, 20)に従うnoise
-
被説明変数
- 試験の得点
: 学習意欲Y と特講の受講X に依存するD Y = 0.5X + treatmentD + noise -
は、正規分布(0, 10)に従うnoise -
は、一様分布(10, 30)に従うtreatment -
は、Y を満たす整数0 \leq Y \leq 100
潜在的結果変数も含めた被説明変数
便宜上、潜在的結果変数(本来であれば観測できないデータ)も含めて生成します。
-
: 特講を受講していなかった場合の試験の得点Y_0 Y = 0.5X + noise
-
: 特講を受講していた場合の試験の得点Y_1 Y = 0.5X + treatment + noise
-
は、正規分布(0, 10)に従うnoise -
は、Y_0, Y_1 を満たす整数0 \leq Y_0, Y_1 \leq 100
Pythonによる実装
Pythonで、上記の条件を満たすデータを生成します。
# ライブラリのインポート
import numpy as np
import pandas as pd
# シードの設定
np.random.seed(0)
# データのサイズ
size = 60
# 学習意欲を表す変数X
X = np.random.uniform(0, 100, size)
# 特講の受講を表す変数D
D_noise = np.random.uniform(-20, 20, size)
D = np.where(X+D_noise>50, 1, 0)
# 試験の得点Y
treatment = np.random.uniform(10, 30, size)
Y_noise = np.random.normal(0, 10, size)
Y = np.clip(0.5*X + treatment*D + Y_noise, 0, 100).astype("int")
# 特講を受講していた場合の得点
Y0 = np.clip(0.5*X + Y_noise, 0, 100).astype("int")
# 特講を受講していた場合の得点
Y1 = np.clip(0.5*X + treatment + Y_noise, 0, 100).astype("int")
# データフレームに格納
df = pd.DataFrame({"X": X, "D": D, "Y": Y, "Y0": Y0, "Y1": Y1})
df.head()
(出力結果)
対象の経済学部生60人中、特講を受講した学生の人数・受講していない学生の人数を確認してみます。
# 特講の受講者数
df["D"].value_counts()
(出力結果)
1 33
0 27
Name: D, dtype: int64
要約統計量やヒストグラムも確認してみます。
# データの概要
display(df.describe())
# ヒストグラムを描画
import matplotlib.pyplot as plt
%matplotlib inline
df[["X", "Y", "Y0", "Y1"]].hist(figsize=(8, 6), sharex=True, sharey=True)
plt.xticks(np.arange(0, 110, 20))
plt.yticks(np.arange(0, 16, 3))
plt.show()
(出力結果)
要約統計量やヒストグラムを見てみると、学習意欲
反実仮想(反事実)
反実仮想とは、「実際には〜したが、仮に〜しなかったとしたら...」と、実際の選択とは別の選択をした"if"のケースを想定することです。
先ほどの「特講の受講と試験の得点」を例に挙げますと、
- 実際には特講を受講したが、仮に特講を受講しなかったとしたら...
- 実際には特講を受講しなかったが、仮に特講を受講したとしたら...
というのが反実仮想になります。
結果変数と潜在的結果変数
とある学生「iさん」の、試験の得点を
そして、「iさん」が特講を受講した場合を
このときに重要なのが、"
そして、実際に観測できた(存在する)方の変数を結果変数、観測できない(存在しない)方の変数のことを潜在的結果変数と言います。
- 「iさん」が特講を受講した場合
- 結果変数: 特講を受講した場合の試験の得点
Y^i_1 - 潜在的結果変数: 特講を受講しなかった場合の試験の得点
(存在しない)Y^i_0
- 結果変数: 特講を受講した場合の試験の得点
- 「iさん」が特講を受講しなかった場合
- 結果変数: 特講を受講しなかった場合の試験の得点
Y^i_0 - 潜在的結果変数: 特講を受講しなかった場合の試験の得点
(存在しない)Y^i_0
- 結果変数: 特講を受講しなかった場合の試験の得点
Pythonによる実装
実際には存在しない潜在的結果変数
- 「実際には特講を受講したが、仮に特講を受講しなかった場合の得点」
- 「実際には特講を受講しなかったが、仮に特講を受講した場合の得点」
を各々5つずつ出力します。
# 実際には特講を受講したが、仮に特講を受講しなかった場合の得点
df_D1 = df[df["D"]==1]
display(df_D1["Y0"].head())
# 実際には特講を受講していないが、仮に特講を受講した場合の得点
df_D0 = df[df["D"]==0]
display(df_D0["Y1"].head())
(出力結果)
1 24
2 15
5 38
6 45
7 54
Name: Y0, dtype: int64
0 55
3 54
4 41
9 46
14 17
Name: Y1, dtype: int64
しつこいですが、実際に分析を行う際にはこれらのデータは存在しません。
あくまでもコードを読みながら、潜在的結果変数とはこのようなものだというイメージをしていただけたらと思います。
因果効果
因果効果とは、「施策が、ある変数に与える影響」のことを指します。
先ほどの「特講の受講と試験の得点」を例に挙げますと、「特講を受講したことによって、特講を受講しなかった場合よりもどれだけ試験の得点が変動したか」が因果効果にあたり、「iさん」の試験の得点に対する因果効果は
一見、因果効果は簡単に求められそうですが、現実問題では
個体レベルの因果効果(ITE)
個体レベルの因果効果(ITE: Individual Treatment Effect)とは、その名の通り個体レベルのデータを元に計算された因果効果です。
「特講の受講と試験の得点」を例に挙げますと、先ほど、現実では計算できないと説明した「iさん」の試験の得点に対する因果効果のことで、
Pythonによる実装
今回は自作の疑似データであるため、ITEが計算できる仕様となっており、計算結果を5つ出力します。
# 個体レベルの因果効果(ITE)
df["ITE"] = df["Y1"] - df["Y0"]
df["ITE"].head()
(出力結果)
0 24
1 20
2 29
3 23
4 19
Name: ITE, dtype: int64
しつこいですが、実際に分析を行う際にはこれらは容易に計算できません。
あくまでもコードを読みながら、ITEとはこのようなものだというイメージをしていただけたらと思います。
平均処置効果(ATE)
平均処置効果(ATE: Average Treatement Effect)とは、グループ全体にもたらした影響の期待値(平均) を表す因果効果です。
「特講の受講と試験の得点」を例に挙げますと、対象となるすべての経済学部生のITEの期待値がATEにあたり、
Pythonによる実装
自作の疑似データをもとにATEを算出します。
# 平均処置効果(ATE)
df["Y1"].mean() - df["Y0"].mean()
(出力結果)
19.749999999999996
一般的に、因果推論や効果検証を実施するという場合には、ATEを算出することを意味します。
実際に分析を行う際は、これほど容易にATEを算出できるパターンは少なく、さまざまな仮定や介入操作の下で因果推論手法を利用し、ATEを算出を実現します。
処置群における平均処置効果(ATT)
処置群における平均処置効果(Average Treatment effect on Treated)とは、実際に処置を受けた集団におけるATEです。
「特講の受講と試験の得点」を例に挙げますと、「実際に特講を受講した学生のITEの期待値」がATTであり
Pythonによる実装
自作の疑似データをもとにATTを算出します。
# 処置群における平均処置効果(ATT)
df_D1["Y1"].mean() - df_D1["Y0"].mean()
(出力結果)
21.575757575757578
ATTを確認することで、実施した施策にどれだけの効果があったかを解釈することができます。
対照群における平均処置効果(ATU)
対照群における平均処置効果(Average Treatment effect on Untreated)とは、実際には処置を受けていない集団におけるATEです。
「特講の受講と試験の得点」を例に挙げますと、「実際に特講を受講しなかった学生のITEの期待値」がATUであり
Pythonによる実装
自作の疑似データをもとにATUを算出します。
# 対照群における平均処置効果(ATU)
df_D0["Y1"].mean() - df_D0["Y0"].mean()
(出力結果)
17.51851851851852
ATUを確認することで、まだ施策が実施されていない対照群に対しても施策を実施するべきかを評価することができます。
セレクション・バイアス
因果効果を算出する上で、犯してしまいがちな過ちが、単純に結果変数の期待値
「特講の受講と試験の得点」を例に挙げますと、「特講を受講した学生の得点の平均」と「特講を受講していない学生の得点の平均」の差を評価してしまうことが、上記の過ちにあたります。
何が問題なのかというと、「特講の受講
もう少し具体的に説明すると
- 学習意欲の高い学生は
- そもそも(特講を受講するしないにかかわらず)試験の得点
が高い上にY - 特講も受講する
D=1
- そもそも(特講を受講するしないにかかわらず)試験の得点
- 学習意欲の低い学生は
- そもそも(特講を受講するしないにかかわらず)試験の得点
が低い上にY - 特講も受講しない
D=0
- そもそも(特講を受講するしないにかかわらず)試験の得点
というケースが多いため、
- 試験の得点&Y&が高いのは、
- 特講を受講した
からだけでなくD=1 - そもそも学習意欲
が高いためX
- 特講を受講した
- 試験の得点
が低いのはY - 特講を受講しなかった
からだけでなくD=0 - そもそも学習意欲
が低いためX
- 特講を受講しなかった
というように、特講の受講とは別の要因も試験の得点
こちらの例のように、特講の受講とは別の要因が試験の得点
もう少し一般的に説明すると、セレクション・バイアスとは単純な結果変数の期待値(平均)とATEの差の量のことであり、
と表されます。ここで
Pythonによる実装
自作の疑似データをもとに単純な結果変数の期待値とセレクション・バイアスを算出します。
# 特講を受講した学生と受講していない学生の平均得点の差
ave = df_D1["Y1"].mean() - df_D0["Y0"].mean()
print(f"特講の受講有無による平均得点の差: {ave}")
# セレクション・バイアス
ATE = df["Y1"].mean() - df["Y0"].mean()
print(f"セレクション・バイアス: {ave - ATE}")
(出力結果)
特講の受講有無による平均得点の差: 39.52861952861953
セレクション・バイアス: 19.778619528619533
因果推論では、いかにこのセレクション・バイアスを取り除いて効果を推定できるかがポイントとなってきます。
参考文献
- 中室、津川「原因と結果の経済学」ダイヤモンド社(2017)
- 伊藤「データ分析の力 因果関係に迫る思考法」光文社新書(2017)
- 岩波データサイエンス刊行委員会編「岩波データサイエンスVol.3-[特集]因果推論-実世界のデータから因果を読む」岩波新書(2016)
- 安井「効果検証入門」ホクソエム社(2020)
- 西山、新谷、川口、奥井「New Liberal Arts Selection 計量経済学」有斐閣(2019)
おわりに
実際にデータ分析業務で因果推論を行ったり、因果推論のテキストで理論的な背景を学習していると、意外と平均処置効果のような基本的な概念がイメージしづらいことがあると思います。そのようなときに、疑似データを自作して、潜在的結果変数やさまざまな因果効果が容易に導出してみることで、さまざまな因果推論手法の理論的な背景もイメージしやすくなると思いますので、参考にしていただけたら幸いです。
他にも下記のような記事を書いています。ご一読いただけますと幸いです。
- 相関関係と因果関係と疑似相関
- 介入とランダム化比較試験
- 回帰分析を用いた効果検証
- 層別解析を用いた効果検証
- 傾向スコアを用いた効果検証
- 操作変数を用いた効果検証
- 回帰不連続デザインを用いた効果検証
- 差分の差分法を用いた効果検証
- 機械学習を用いた効果検証
また、過去にLTや勉強会で発表した資料は下記リンクにまとめてあります。ぜひ、ご一読くださいませ。
Discussion