🐍

Pythonで因果推論(7)~操作変数(IV)を用いた効果検証~

2022/06/25に公開

はじめに

操作変数法を用いた因果推論手法について、Pythonによる実装を交えてまとめました。内容について誤り等ございましたら、コメントにてご指摘いただけますと幸いです。

操作変数の概要

操作変数

操作変数(IV: Instrumental Valiable)とは、処置には影響を与えるものの、被説明変数には処置を通してのみしか影響を与えない変数です。

操作変数を用いることで

  • 脱落変数バイアス(欠落変数バイアス)
  • 同時決定・内生性バイアス

が生じている場合にも、因果効果の推定が可能になります。

次のようなモデルのもと、操作変数IVを用いてパラメータb_Dを推定することを考えます。

Y_i = b_0 + b_D D_i + u_i
ただし
u_i 〜 N(0, \sigma^2), \: Cov(D_i, u_i) ≠ 0
このとき、操作変数IVが満たす条件は次の通りです。

  1. 操作変数IVは処置変数Dと相関がある(Cov(IV_i, D_i) ≠ 0)
  2. 操作変数IVは誤差項uとは無相関(Cov(IV_i, u_i) = 0)

上記は、説明変数(内生変数)と操作変数がひとつずつの場合の条件です。一般の場合の操作変数が満たすべき条件はもう少し複雑になるため、本記事では割愛させていただきます。

操作変数法

操作変数法(IV法: Instrumental Valiable method)とは操作変数(IV)を用いて処置の被説明変数への因果効果を推定する解析方法です。

先ほどと同様のY_i = b_0 + b_D D_i + u_iというモデルでは、条件を満たす操作変数IVを用いてパラメータb_Dを次のように推定することができます。

\hat{b^{IV}_D} = \frac{Cov(IV, Y)}{Cov(IV, D)} = \frac{\sum_{i=1}^N(IV_i - \bar{IV})(Y_i - \bar{Y})}{\sum_{i=1}^N(IV_i - \bar{IV})(D_i - \bar{D})}
こちらは2段階最小二乗法という手法でも算出することができます。

2段階最小二乗法

2段階最小二乗法(2SLS: TSLS: Two-Stage Least Squares)とは、その他の通り2段階で最小二乗法(OLS)を実行する推定手法です。

先ほどと同様のY_i = b_o + b_DD_i + u_iというモデルを考えると、操作変数IVを用いた2段階最小二乗法は次のような流れでパラメータb_Dを推定します。

1段階目

まず、処置変数D_iを被説明変数、操作変数IV_iを説明変数とする次のような回帰モデルを考えます。

D_i = \pi_0 + \pi_{IV}IV + v_i
このモデルで最小二乗法(OLS)を実行し、D_iの予測値\hat{D}_iを算出します。

2段階目

先ほど算出した予測値\hat{D}_iD_iに代入します。

Y_i = b_o + b_D \hat{D}_i + u_i
このモデルで最小二乗法(OLS)を実行して得られたパラメータb_Dが、2SLS推定量\hat{b}^{2SLS}_Dであり、
\hat{b}^{2SLS}_D = \frac{\sum_{i=1}^N(\hat{D}_i - \bar{\hat{D}})(Y_i - \bar{Y})}{\sum_{i=1}^N(\hat{D}_i - \bar{\hat{D}})^2}
と表されます。

Pythonによる実装

設定

とある大学の経済学部生200人を対象に、夏季休暇期間に計量経済学の特別講義(特講)を開催し、その効果を考えます。特講を開催するにあたって受講対象生(約半数)に対してランダムに特講開催の紹介メールを送信しています。夏季休暇終了後に、特講の受講にかかわらず対象者200人に対して計量経済学の試験を実施し、その得点のデータを観測します。

  • 学習意欲X(観測不能な交絡因子)
    • 学生の学習意欲を0以上1以下の数値で表したもの
    • 一様分布(0, 1)に従う
    • 特講の受講Dと試験の得点Yに影響を与える
  • メール受信ダミーIV(操作変数)
    • 特講開催の紹介メールが届いたかどうかを表すダミー変数
    • メールはランダムに割り当てられている
  • 特講受講ダミーD(処置変数)
    • 学生が特講を受講したかどうかを表すダミー変数
    • D=1であれば特講を受講したことを、D=0であれば特講を受講していないことを表す
    • 学習意欲Xとメール受信ダミーIVに依存しており、
      0.3 \times X + 0.4 \times IV + noise
      の値が0.5以上であれば特講を受講(D=1)、0.5未満であれば特講を未受講(D=0)とする(ただし、noiseは一様分布(0, 0.3)に従う)
  • 試験の得点Y(被説明変数)
    • 学生の試験の得点を表し、真のモデルは
      Y = 50 \times X + 20 \times D + noise
      で表現される(ただし、noiseは、平均0、標準偏差10の正規分布に従う)

データの作成

Pythonで上記の設定を満たすデータを作成します。

# 必要なライブラリをインポート
import numpy as np
import pandas as pd

# シードの設定
np.random.seed(0)
# データのサイズ
size = 200

# 学習意欲を表す変数X(観測不能な交絡因子)
X = np.random.uniform(0, 1, size)
# メール送信ダミーIV
IV = np.random.choice([0, 1], p=[0.5, 0.5], size=size)
# 特講受講ダミーD
D_noise = np.random.uniform(0, 0.3, size)
D_threshold = 0.3*X + 0.4*IV + D_noise
D = np.where(D_threshold>=0.5, 1, 0)

# 試験の得点Y
Y_noise = np.random.normal(0, 10, size)
Y = np.clip(50*X + 20*D + Y_noise, 0, 100).astype("int")

# データフレームに格納し、5つだけ出力
df = pd.DataFrame({"メール受信ダミー": IV, "特講受講ダミー": D, "試験の得点": Y})
df.head()

(出力結果)

操作変数法による効果検証

本来、試験の得点Yに寄与している変数は学習意欲Xと特講受講ダミーDです。さらに学習意欲Xは特講受講ダミーDにも影響を与える交絡因子となっています。しかし、学習意欲Xは観測不能なため、操作変数IVを用いて特講受講ダミーDのパラメータを推定します。

Y_i = b_o + b_DD_i + u_iというモデルの下で操作変数IVを用いると、パラメータb_Dは次のように推定できます。

\hat{b}_D^{IV} = \frac{\sum_{i=1}^N(IV_i - \bar{IV})(Y_i - \bar{Y})}{\sum_{i=1}^N(IV_i - \bar{IV})(D_i - \bar{D})}
これをPythonで計算します。

np.sum((IV - IV.mean())*(Y - Y.mean())) / np.sum((IV - IV.mean())*(D - D.mean()))

(出力結果)

17.011952191235057

b_Dの真の値は20なので多少下振れした推定値になりました。

2段階最小二乗法による効果検証

1段階目

まずは、操作変数IVを用いて処置変数Dを推定します。

D_i = \pi_0 + \pi_{IV}IV + v_i
というモデルでOLSを実行します。

# 必要なライブラリのインポート
import statsmodels.api as sm

# 説明変数
IV = df[["メール受信ダミー"]]
IV = sm.add_constant(IV)
# 被説明変数
D = df["特講受講ダミー"]

# モデルの設定(OLS:最小二乗法を指定)
model1 = sm.OLS(D, IV)

# 推定値を出力
result1 = model1.fit()
result1.predict(IV)

(出力結果)

0      0.066667
1      0.947368
2      0.066667
3      0.066667
4      0.066667
         ...   
195    0.947368
196    0.066667
197    0.066667
198    0.066667
199    0.066667
Length: 200, dtype: float64

これでDの推定値\hat{D}を算出することができました。

2段階目

Dの推定値を利用して、パラメータb_Dを推定します。

Y_i = b_0 + b_D \hat{D} + u_i
というモデルでOLSを実行します。

# 説明変数(Dの推定値を利用)
D_hat = result1.predict(IV)
D_hat = sm.add_constant(D_hat)
# 被説明変数
Y = df["試験の得点"]

# モデルの設定(OLS:最小二乗法を指定)
model2 = sm.OLS(Y, D_hat)

# OLSの結果を出力
result2 = model2.fit()
print(result2.params)

(出力結果)

const    24.999203
0        17.011952

これでパラメータb_D\hat{b}^{2SLS}_D = 17.011952と推定されました。この推定結果は先ほど算出した操作変数推定量\hat{b}^{IV}_Dと同じ値であることが分かります。

参考文献

おわりに

最後まで読んでいただきありがとうございました。他にも「Python×データ分析」をメインテーマに記事を執筆しているので、参考にしていただけたら幸いです。内容の誤り等がございましたら、コメントにてご指摘くださいませ。

他にも下記のような記事を書いています。ご一読いただけますと幸いです。

また、過去にLTや勉強会で発表した資料は下記リンクにまとめてあります。ぜひ、ご一読くださいませ。
https://speakerdeck.com/s1ok69oo

Discussion