LaLondeデータセットに対して EConMLのDoubly Robust 推定を使って因果推論

# はじめに

前回書いた記事[LaLondeデータセットに対し傾向スコア（IPW）をPythonで実装して因果推論](https://qiita.com/shinji_komine/items/2216e948ea356bc9c37b)では、就労支援の効果に関する（人為的に作り出した）観察データであるLaLondeデータセットに対して、傾向スコアによる逆確率重み付き推定（IPW）で因果効果を推定しました。このデータでは対照群のデータ件数が多い不均衡データであるため、対照群のサンプルは大半が0に近い傾向スコアとなり、これの逆数である重みはわずかな誤差で不安定となってしまうことが原因でした。

今回は、傾向スコアとIPWを使った手法の発展形である **Doubly Robust** 推定を実施してみます。この推定をPythonで実施する際には、MicroSoftが提供しているライブラリ `EconML` を使います。初めにDoubly Robust 推定について説明して、それからEConMLを使って実際に就労支援の効果を推定します。
前回説明したので、今回はLaLondeデータセットなどに関しては説明しません。興味ある方は前回の[記事](https://qiita.com/shinji_komine/items/2216e948ea356bc9c37b)をご参照ください。

# Doubly Robust 推定
IPWでは介入群に対する効果を以下のように推定しました。
$$
\frac{1}{N} \Sigma_i \frac{z_i y_{i}}{\hat{e}_i} \quad \quad (1)
$$

ここで、
- $N$ : データの標本数
- $z_i$  : $i$番目の人の介入ダミー変数。就労支援を受けていれば1、受けていなければ0
- $y_i$ : $i$番目の人の'78における収入
- $\hat{e}_i$ : $i$番目の人の推定された傾向スコア

Doubly Robust 推定では以下の推定量を用います。

$$
\tau_1 = \frac{1}{N} \Sigma_i \[ \frac{z_i y_i}{\hat{e}_i} + \( 1 - \frac{z_i}{\hat{e}_i} \) \hat{m}(x_i) \] \quad \quad (2)
$$   

ここで $\hat{m}(x_i)$は回帰分析などで推定された因果効果量です。前回の例では線形モデルを仮定して推定していました。
この$\tau_1$は、以下の２つのうちどちらか1つの条件が満たされていれば、$E[\tau_1] = E[Y_1]$ となることが知られています。ここで$Y_1$は**介入が入ったとき**の結果変数（ここでは'78の収入）です。

-  因果効果のモデルが正しく推定されている、すなわち $\hat{m}_1(X) = E[Y_1|X] $
-  傾向スコアが正しく推定されている、すなわち $\hat{e}(X) = P(Z=1|X)$

この意味で、Doubly Robust （二重に頑健）な推定という名前がついています。この記事の末尾に、一応証明を付けておきました。興味がある方はご参照ください。


# EConML

Doubly Robust など、複雑な因果推論を実行するライブラリとして、Microsoftが提供している`EConML`があります。EConMLのドキュメントは[こちら](https://econml.azurewebsites.net/)です。
実験データ、観察データどちらの因果推論もできるようになっています。
Doubly Robust 以外にも、いろんな手法が用意されています。どのような時に、どの手法を使うべきかを選択できるように[ライブラリのフローチャート](https://econml.azurewebsites.net/spec/flowchart.html)が用意されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225870/908b97a0-ae86-80de-18df-526243c19175.png)

ただし、このフローチャートでは因果推論の用語が使われていますので、正しい方法を選ぶためには基礎知識は必要となっています。

今回はDoubly Robust を実行する `DRLearner` に焦点を絞ります。

# 線形モデルとロジスティックでDoubly Robust

EConMLのDRLearnerを使って、まずは以下のモデルで推定してみます。

- 因果効果モデル：線形モデル
- 傾向スコアモデル：ロジスティック回帰モデル

始めに、前回同様NSWとCPSのデータを読み込み、LaLondeデータセットを作ります。
```python
nsw_data = pd.read_stata("https://users.nber.org/~rdehejia/data/nsw_dw.dta")
cps1_data = pd.read_stata("https://users.nber.org/~rdehejia/data/cps_controls.dta")
nsw_cps1_data = pd.concat( [nsw_data.query("treat==1"), cps1_data], axis=0 )
```

このデータに対して、`LinearDRLearner`を実行します。

```python
from econml.dr import DRLearner, LinearDRLearner
from sklearn.linear_model import LinearRegression, LogisticRegression

X = nsw_cps1_data[['age', 'education', 'black', 'hispanic', 'married', 'nodegree', 're74', 're75']]
y = nsw_cps1_data['re78']
T = nsw_cps1_data['treat']

est = LinearDRLearner(
  model_propensity=LogisticRegression(max_iter=10000, penalty='none', random_state=1),
  model_regression=LinearRegression(), 
  random_state=2, cv=5)

est.fit(y, T, X=X, W=None)
```

`fit()`メソッドでモデルを推定しています。推定したモデルを使って因果効果を計算するときは`ate()`メソッドを使います。

```python
print(est.ate(X))
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225870/37a7c2d6-45d7-721d-d3fa-b3365d3b0948.png)

就労支援の介入により、収入は3005ドル減少したと推定されてしまい、実際とは逆の結果となっています。
前回、因果効果のモデルとして線形モデル、傾向スコアとしてロジスティック回帰モデルをそれぞれ使い、推定された因果効果は真の値からはずれていることを見ました。このモデル２つを同時に使っても、モデルの当てはまりが改善されるわけではないのでしょう。Doubly Robustは因果効果モデルと傾向スコアのどちらか１つが正しければ、良い推定量となります。２つとも当てはまりが悪い場合は、結局良い推定量とはならないことを確認したことになったようです。

# ランダムフォレストでDoubly Robust

次に、以下のモデルの組み合わせでDoubly Robust推定を実施します。

- 因果効果モデル：ランダムフォレスト回帰モデル
- 傾向スコアモデル：ランダムフォレスト分類モデル

それぞれのランダムフォレストモデルのハイパーパラメータはGridSearchで決定することにします。
EConMLの`DRLearner`を呼び出す前にGridSearchを実行する関数を定義しておき、以下のように実装します。

```python
from sklearn.linear_model import LinearRegression, LogisticRegression
from sklearn.model_selection import GridSearchCV

model_reg = lambda: GridSearchCV(
                    estimator=RandomForestRegressor(random_state=1),
                    param_grid={
                        'max_depth': [3, 5, 10],
                        'min_samples_leaf':[10,20,50],
                        'n_estimators': (100, 200, 500)
                    }, cv=5, n_jobs=-1, scoring='neg_mean_squared_error'
                )
model_clf = lambda: GridSearchCV(
                estimator=RandomForestClassifier(min_samples_leaf=10, random_state=1),
                param_grid={
                        'max_depth': [3, 5, 10],
                        'n_estimators': (100, 200, 500)
                     }, cv=5, n_jobs=-1, scoring='neg_mean_squared_error'
                )
est3 = DRLearner(model_regression=model_reg(), model_propensity=model_clf(),
               model_final=model_reg(), cv=5, random_state=1)
est3.fit(y, T, X=X, W=None)

est3.ate(X)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225870/fae1877a-7d86-d56b-81e1-63be3e0a48aa.png)

今度は、就労支援の介入効果で、収入は2575ドル増加したと推定されました。真の値1794ドルからはずれていますが、介入によって収入が増えたという結果が得られました。


# まとめ

この記事では、LaLondeデータセットに対してEConMLのDoubly Robust推定を実施しました。
因果効果について線形モデル、傾向スコアについてロジスティック回帰モデルを使った場合、モデルの当てはまりがよろしくないようで、Doubly Robust推定量$(2)$は良い推定量ではありませんでした。
モデルを少し複雑にし、因果効果についてランダムフォレスト回帰モデル、傾向スコアについてランダムフォレスト分類モデルを使うと、介入の効果があったという結果が得られました。

ただし、ランダムフォレストを使った結果でも、乱数（random_state）を変えると、因果効果の数値は2500ドル～5000ドルと変わってしまいました。おそらく、Doubly Robust推定と機械学習モデルを組み合わせても過信は禁物で、汎化性能などを検証しないと正しい結論は得られないと思います。

EConML自体はドキュメントもそれなりに充実していて、扱いも困難ではなく、因果推論を実施する必要が生じたときは有用なライブラリだと思いました。ただし、正しく使うためには扱っている対象の背景の理解、データの理解、モデルの汎化性能の検証などをしっかりやらないと、誤った結果を導いてしまう危険性もあると思いました。

# 参考
[EConML LinearDRLearner](https://econml.azurewebsites.net/_autosummary/econml.dr.LinearDRLearner.html)
[EConML DRLearner](https://econml.azurewebsites.net/_autosummary/econml.dr.DRLearner.html)
GridSearchの利用方法は [EConMLのこのページの下部](https://econml.azurewebsites.net/spec/estimation/dr.html)を参考にしています。
[岩波データサイエンスVol.3](https://www.amazon.co.jp/%E5%B2%A9%E6%B3%A2%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%A8%E3%83%B3%E3%82%B9-Vol-3-%E5%B2%A9%E6%B3%A2%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%A8%E3%83%B3%E3%82%B9%E5%88%8A%E8%A1%8C%E5%A7%94%E5%93%A1%E4%BC%9A/dp/4000298534/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=33YHLCE0GTF9I&keywords=%E5%B2%A9%E6%B3%A2%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%A8%E3%83%B3%E3%82%B9&qid=1671226030&s=books&sprefix=%E5%B2%A9%E6%B3%A2%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%A8%E3%83%B3%E3%82%B9%2Cstripbooks%2C224&sr=1-1)



# 参考 式(2) が二重に頑健な推定量であることの証明

### 前提
強く無視できる割り当ての仮定が成り立っているものとする。
$ \\{ Y_1, Y_0 \\} \perp Z | X$ 

これは、共変量Xが与えられれば、$Y_1$と$Y_0$は介入群と対照群のどちらに割り当てられるかによらずに決まることを意味しており、結構強い仮定です。

### 証明

```math
\tau_1 = \frac{Z}{\hat{e}(X)}Y + (1 - \frac{Z}{\hat{e}(X)}) \hat{m}_1(X)
```

$\tau_1$は下式のように書き換えられます。

```math
\tau_1 = Y_1 + \frac{Z - \hat{e}(X)}{\hat{e}(X)}(Y_1 - \hat{m}_1(X))
```

ここで、$Y=Z Y_1 + (1-Z)Y_0$ 、 $Z(1-Z) = 0$を使っています。

この右辺第2項の期待値が0になれば、$E[\tau_1] = E[Y_1]$ となり、介入効果に関する良い推定量となります。

確率変数X,Y,Zで期待値をとる演算を$E_{XYZ}[f(X,Y,Z)]$と書きます。 $E_{XYZ} = \Sigma_x \Sigma_y \Sigma_z f(x,y,x) P(x, y, z)$です。$P(X,Y,Z) = P(Y|X,Z)P(X,Z)$ より、$E_{XYZ}[f] = E_{X,Z}[ E_{Y|XZ}[f] ]$が成り立ちます。

-  $\hat{m}_1(X) = E[Y_1|X] $のとき

```math
\begin{aligned}
E_{XYZ} [ \frac{Z-\hat{e}(X)}{\hat{e}(X)} ( Y_1 - \hat{m}_1(X) ) ] &= 
E_{XZ}[ E_{Y_1|XZ} \{ \frac{Z-\hat{e}(X)}{\hat{e}(X)}(Y_1 - \hat{m}_1(X)) \} ] \\
&=E_{XZ}[ \frac{Z-\hat{e}(X)}{\hat{e}(X)} \{ E_{Y_1|XZ}[Y_1] - \hat{m}_1(X) \}] \\
&=E_{XZ}[ E[Y_1|X] - E[Y_1|X] ] \\ &= 0
\end{aligned}
```

2行目から3行目では、強く無視できる割り当ての仮定より、$E_{Y_1|XZ}[Y_1] = E_{Y_1|X}[Y_1]$ を使っています。

- $\hat{e}(X) = P(Z=1|X)$ のとき

```math
\begin{aligned}
E_{XYZ} [ \frac{Z-\hat{e}(X)}{\hat{e}} ( Y_1 - \hat{m}_1(X) ) ] &=
E_{X Y_1}[ E_{Z|X Y_{1}} \{  \frac{Z-\hat{e}(X)}{\hat{e}(X)}(Y_1 - \hat{m}_1(X))  \}  ] \\
&= E_{X Y_{1}} [  (Y_1 - \hat{m}_1(X)) E_{Z|X Y_1} \{ \frac{Z-\hat{e}(X)}{\hat{e}(X)} \} ] \\
&= E_{X Y_{1}} [  (Y_1 - \hat{m}_1(X)) \{ \frac{1}{\hat{e}(X)}E_{Z|X Y_1}(Z) - 1 \} \\
&= E_{X Y_{1}} [  (Y_1 - \hat{m}_1(X)) \{ \frac{\hat{e}(X)}{\hat{e}(X)} -1 \} \\
& = 0
\end{aligned}
```

3行目から4行目では、強く無視できる割り当ての仮定より、$E_{Z|XY}(Z) = E_{Z|X}(Z)$を使っています。

よって、  $\hat{m}_1(X) = E[Y_1|X]$ のとき、あるいは $\hat{e}(X) = P(Z=1|X)$ のときに 

$E_{XYZ}[\tau_{1}] = E_{XYZ}[Y_{1}]$

が成り立ちます。