Propensity score & Conditional Independence Assumption

条件付き期待値の基本的理解 2/N

公開日: 2023-07-06
更新日: 2023-11-18

  Table of Contents

条件付き独立とPropensity score

Propensity Score Theorem

$X_i$ がcovariates vector, $D_i$ がbinary treatmentを指すとする. 以下のようにPotential Outcome ${Y_{1i}, Y_{0i}}$ に対してConditional Independence Assumption(CIA)が成立するとする:

\[\{Y_{1i}, Y_{0i}\} \perp D_i |X_i\]

このとき,

\[\{Y_{1i}, Y_{0i}\} \perp D_i |p(X_i) \text{ s.t } \mathbb E[D_i|X_i] \equiv p(X_i)\]

が成立する

2022年時点に会社Aに在籍している人を対象に以下のデータを集めたとします

  • $D_i$: 2022年時点での会社提供スキルアップクラス受講ステータス
  • $Y_i$: 2022年開始時点での推定年収と2023年期末時点での年収の差分
  • $X_i$: 従業員の属性

会社提供スキルアップクラス受講のyes, noは個人の自発的意思に任されているとします. この状況下でスキルアップクラス受講の 翌年年収への影響を推定したいときに,単純比較を実施してしまうと

\(\begin{align*} \mathbb E[Y | D_i=1] - \mathbb E[Y | D_i=0] &=\mathbb E[Y_1 | D_i=1] - \mathbb E[Y_0 | D_i=0]\\ &= (\mathbb E[Y_1 | D_i=1] - \mathbb E[Y_0 | D_i=1]) + (\mathbb E[Y_0 | D_i=1] - \mathbb E[Y_0 | D_i=0])\\ &= \text{ATT } + \text{selection bias } \end{align*}\)

以上のようにATT + selection biasのように見たい効果が見ることができません. また, そもそも会社の意思決定問題に応じて「見たい効果」というのも変わってきます. 例えば,

  1. スキルアップクラス受講を廃止したい
  2. スキルアップクラス受講を強制したい
  3. スキルアップクラス受講を強制したときに, 他の施策との効果を比較したい

というそれぞれのケースを考えた場合, (1)ならばATT(=Average Treatment effect on the treaed)を知りたいですし, (2)ならばATU(=Average Treatment effect on the untreaed), (3)ならば ATE / 一人あたり実施コストを知りたいと考えられます.

意思決定問題と照らし合わせて, 見たい指標が決まったとしても, 単純比較ではいずれも見ることができません.

じゃあ, 「どうやって ATE, ATT, ATUを推定すべきか?」という問題が出てきますがとのとき便利なAssumptionがCIAです

\[\{Y_{1i}, Y_{0i}\} \perp D_i |X_i\]

これは指し示すことは簡単に言うと,

  • スキルアップクラス受講ステータスについて, 特徴量で説明した後に発生するノイズはPOMの分布と関係ないと確信を持っている
  • 分析者はこれらの特徴量が観察できる

ということです. これが成立していると仮定できると, 実際に観察できない

\[\mathbb E[Y_0 | D_i=1], \mathbb E[Y_1 | D_i=0]\]

が推定できるようになります.

CIAが成立するならばなぜCounter-factualが導けるのか?

$\mathbb E[Y_1 \vert D_i=0]$をなぜ推定できるようになるのか簡単に以下示します:

$S_0$をunteatedの特徴量$X_i$の特徴量空間としたときに

\(\begin{align*} \mathbb E[Y_1 | D_i=0] &= \mathbb E[\mathbb E[Y_1| D_i=0, X_i] | D_i=0]\\ &= \mathbb E[\mathbb E[Y_1|X_i] | D_i=0] \ \ \ \ \because \text{ CIA}\\ &= \sum_{x\in S_0} \mathbb E[Y_1|X_i = x]\Pr(X_i=x |D_i = 0)\\ &= \sum_{x\in S_0} \mathbb E[Y_1|D_i = 1, X_i = x]\Pr(X_i=x |D_i = 0) \because \text{CIA and support condition} \end{align*}\)

なお, Support conditionとは

\[\Pr(X_i=x |D_i = 1) > 0 \ \ \forall x \in S_0\]

のことです. とある $x \in S_0$ について

\[\Pr(X_i=x |D_i = 1) = 0\]

だと, Counter-factualが計算できなくなってしまいます. 一方, ATUを推定するにあたって

\[\Pr(X_i=x |D_i = 0) = 0\]

は問題になりません. なぜならば, ATUを推定したいときのpopulationは $D_i = 0$の従業員ですが, $\Pr(X_i=x \vert D_i = 0) = 0$のような特徴量水準$x$はそのpopulationに属していないからです.

これは$\Pr(X_i=x \vert D_i = 0) = 0$ならば, $x\not\in S_0$というところからも直感的にはわかります.

Propensity scoreでコントロールするとなぜCIAが成立するのか?

Propensity scoreは特徴量のバランシングスコアである

balancing Score

$ \mathbb E[D_i\vert X_i] \equiv p(X_i)$ のとき,

\[D_i \perp X_i|p(X_i)\]

が成立する.

この証明は$Pr(D_i\vert X_i, p(X_i)) = Pr(D_i\vert p(X_i))$の証明ができればOkです. なぜなら

\(\begin{align*} &\Pr(D_i|X_i, p(X_i)) = \Pr(D_i|p(X_i))\\ &\Rightarrow \Pr(D_i, X_i|P(X_i)) = \Pr(D_i|X_i, p(X_i)) \Pr(X_i| p(X_i))\\ &= \Pr(D_i|p(X_i))\Pr(X_i| p(X_i)) \end{align*}\)

$\Pr(D_i\vert X_i, p(X_i)) = \mathbb E[D_i\vert X_i, p(X_i)]$であることに留意すると,

\(\begin{align*} \mathbb E[D_i|X_i, p(X_i)] &= \mathbb E[D_i|X_i] = p(X_i)\\ \mathbb E[D_i|p(X_i)] &= \mathbb E[\mathbb E[D_i|X_i, p(X_i)]|p(X_i)]\\ &= \mathbb E[p(X_i)|p(X_i)] = p(X_i) \end{align*}\)

したがって,

\(\begin{align*} \Pr(D_i|X_i, p(X_i)) &= \mathbb E[D_i|X_i, p(X_i)] \\ &= \mathbb E[D_i|p(X_i)]\\ &= \Pr(D_i|p(X_i)) \end{align*}\)

したがって,

  • 適切なpropensity scoreで条件付けると特徴量$X_i$はtreatment status$D_i$と独立になる.
  • 言い換えると, 適切なpropensity scoreで条件付けると特徴量$X_i$の分布は$D_i$とバランスされる.

Propensity scoreで条件づけたPotential outcome

Propensity score theorem

$X_i$ がcovariates vector, $D_i$ がbinary treatmentを指すとする. 以下のようにPotential Outcome ${Y_{1i}, Y_{0i}}$ に対してConditional Independence Assumption(CIA)が成立するとする:

\[\{Y_{1i}, Y_{0i}\} \perp D_i |X_i\]

このとき,

\[\{Y_{1i}, Y_{0i}\} \perp D_i |p(X_i) \text{ s.t } \mathbb E[D_i|X_i] \equiv p(X_i)\]

が成立する

MHE version 証明

MHEにならって以下のように証明できます.

${Y_{1i}, Y_{0i}} \perp D_i \vert p(X_i)$が成立することを言い換えると

\[\begin{align*} \Pr(D_i=1|Y_{1i}, Y_{0i}, p(X_i)) = \Pr(D_i=1|p(X_i)) = p(X_i) \end{align*}\]

なのでこれを示せれば十分ということがわかります.

\(\begin{align*} \Pr(D_i=1|Y_{1i}, Y_{0i}, p(X_i)) &= \mathbb E[D_i|Y_{1i}, Y_{0i}, p(X_i)]\\[3pt] &= \mathbb E[\mathbb[D_i|Y_{1i}, Y_{0i}, X_i]|Y_{1i}, Y_{0i}, p(X_i)]\\[3pt] &= \mathbb E[\mathbb[D_i|X_i]|Y_{1i}, Y_{0i}, p(X_i)] \because \text{ CIA holds}\\[3pt] &= \mathbb E[p(X_i)|Y_{1i}, Y_{0i}, p(X_i)] \because \text{ definition}\\[3pt] &= p(X_i) \end{align*}\)

したがって, ${Y_{1i}, Y_{0i}} \perp D_i \vert p(X_i)$が成立する.

関数変換後の独立性に基づいた証明

$p(X_i)$について, 逆写像$p^{-1}$が定義できるとします. 任意の事象$A, B, C$について

\(\begin{align*} \Pr((Y_{0i}, Y_{1i})\in A, D_i\in B \vert p(X_i)\in C) &= \frac{\Pr((Y_{0i}, Y_{1i})\in A, D_i\in B, p(X_i)\in C)}{\Pr(p(X_i)\in C)}\\[3pt] &= \frac{\Pr((Y_{0i}, Y_{1i})\in A, D_i\in B, X_i\in p^{-1}(C))}{\Pr(X_i\in p^{-1}(C))}\\[3pt] &= \Pr((Y_{0i}, Y_{1i})\in A, D_i\in B \vert X_i\in p^{-1}(C))\\[3pt] &= \Pr((Y_{0i}, Y_{1i})\in A \vert X_i\in p^{-1}(C))\Pr(D_i\in B \vert X_i\in p^{-1}(C)) \\[3pt] &= \Pr((Y_{0i}, Y_{1i})\in A \vert p(X_i)\in C)\Pr(D_i\in B \vert p(X_i)\in C) \end{align*}\)

したがって, ${Y_{1i}, Y_{0i}} \perp D_i \vert p(X_i)$が成立する.

条件付き期待値の独立性

conditional expectationに着目して以下を示すことも可能です:

\[\mathbb E[Y_{ji} | D_i, p(X_i)] = \mathbb E[Y_{ji} | p(X_i)] \text{ for } j = 0,1\]

証明は以下です:

\(\begin{align*} \mathbb E[Y_{ji} | D_i, p(X_i)] &= \mathbb E[\mathbb E[Y_{ji}| D_i, p(X_i), X_i] | D_i, p(X_i)]\\ &= \mathbb E[\mathbb E[Y_{ji}| D_i, X_i] | D_i, p(X_i)]\\ &= \mathbb E[\mathbb E[Y_{ji}| X_i] | D_i, p(X_i)] \because \text{ CIA } \end{align*}\)

このとき, 簡略化のため $\mathbb E[Y_{ji}\vert X_i] \equiv \mu(X_i)$と表記します.

\(\begin{align*} \mathbb E[\mathbb E[Y_{ji}| X_i] | D_i, p(X_i)] &= \mathbb E[\mu(X_i) | D_i, p(X_i)]\\ &= \int_{x\in \Theta_x} \mu(x) f(x|D_i, p(X_i))\\ &= \int_{x\in \Theta_x} \mu(x) f(x|p(X_i)) \because \text{ balancing score peroperty}\\ &= \mathbb E[\mathbb E[Y_{ji}| X_i] | p(X_i)]\\ &= \mathbb E[Y_{ji}| p(X_i)] \because \text{ the smaller info set always dominates} \end{align*}\)

したがって, Propensity scoreで条件付けるとPotential outcomeの期待値は$D_i$に依存しないことがわかります.

Heterogeneous Treatment Effectがある場合

理論的な背景は追いませんが, PythonでHeterogeneityがあるときのPSMを確認してみます. いわずもがなですが, Heterogeneous Treatment effectがある場合にPropensity scoreで条件づけて CATEを推定しにいこうとしても, よくわからないCATEが出てくることを以下確認します.

設定は以下です:

\[\begin{align*} & X_1 \sim Uniform(0, 1) \\ & X_2 \sim Uniform(0, 1) \\ & \Pr(D_i=1|X_i) = \begin{cases} 0.3 & \text{ if } X_1 > 0.5, X_2 \leq 0.5 \\ 0.3 & \text{ if } X_1 \leq 0.5, X_2 > 0.5 \\ 0.5 & \text{ otherwise} \end{cases}\\ & Y_{0i} \sim Normal(0, 1)\\ & \text{uplift } = \begin{cases} 2 & \text{ if } X_1 > 0.5, X_2 \leq 0.5 \\ 2 & \text{ if } X_1 \leq 0.5, X_2 > 0.5 \\ 8 & \text{ if } X_1 > 0.5, X_2 > 0.5 \\ -8 & \text{ otherwise } \end{cases} \end{align*}\]

簡単に言うと, $(x_1, x_2)$によって, 1辺長さ1の空間が四等分され, 各ブロックごとに Treatment effectと割当確率が定まっている状況を考えます.

なお, 分析の簡略化のため, 分析者はTrueの割当確率がわかっているものとします. これは, 分析者が優秀で割当確率のTrue formの推定ができている状況と同じと考えていただけたらです.

DGP and Distribution check

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import numpy as np
import pandas as pd
from plotly.subplots import make_subplots
import plotly.graph_objects as go

np.random.seed(42)

#-------------
# DGP
#-------------

def dgp(effect=[2, 8, -8]):
    N = 10000
    x1 = np.random.uniform(0, 1, N)Heterogeneityの存在
    x2 = np.random.uniform(0, 1, N)

    z1 = np.where(x1 > 0.5, 1, 0)
    z2 = np.where(x2 > 0.5, 1, 0)
    assignment_rule = z1 + z2
    assignment_prob = np.where(assignment_rule == 1, 0.3, 0.5)
    assigment = np.random.binomial(1, assignment_prob)

    potential_untreated = np.random.normal(0, 1, N)
    uplift = np.where(assignment_rule == 1, effect[0], 0.0)\
             + np.where(assignment_rule == 2, effect[1], 0.0) \
             + np.where(assignment_rule == 0, effect[2], 0.0)
    potential_treated = potential_untreated + uplift

    df = pd.DataFrame({
        'x1': x1,
        'x2': x2,
        'prob': assignment_prob,Heterogeneityの存在
        'D': assigment,
        'uplift':uplift, 
        'y0': potential_untreated,
        'y1': potential_treated
    })
    df['observed'] = (1 - df['D']) * df['y0'] + (df['D']) * df['y1']

    return df

df = dgp()
df = dgp()
df.head()
x1 x2 prob D uplift y0 y1 observed
0 0.374540 0.373641 0.5 1 -8.0 -0.630692 -8.630692 -8.630692
1 0.950714 0.332912 0.3 0 2.0 2.140309 4.140309 2.140309
2 0.731994 0.176154 0.3 0 2.0 1.665679 3.665679 1.665679
3 0.598658 0.607267 0.5 1 8.0 0.730935 8.730935 8.730935
4 0.156019 0.476624 0.5 0 -8.0 -0.343076 -8.343076 -0.343076
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
fig = make_subplots(rows=1, cols=2, 
                    subplot_titles=("Assignment Prob distribution", 
                                    "uplift distribution"))
trace1 = go.Scatter(x=df['x1'],
                    y=df['x2'],
                    mode='markers',
                    name='prob',
                    hovertemplate="%{marker.color}%",
                    marker=dict(color=df['prob'], colorscale='bluered'),
                    showlegend=False
                   )
trace2 = go.Scatter(x=df['x1'],
                    y=df['x2'],
                    mode='markers',
                    name='uplift',
                    hovertemplate="%{marker.color}",
                    marker=dict(color=df['uplift'],colorscale='bluered'),
                    showlegend=False
                   )
fig.append_trace(trace1,1,1)
fig.append_trace(trace2,1,2)
fig.update_layout(title_text="Assignment probability and uplift distirbution conditional on X")

1辺長さ1の空間が四等分され, 各ブロックごとに Treatment effectと割当確率が定まっている状況がこれで確認できたと思います.

推定値の確認

まずTrue effectの確認をしてみます.

1
2
3
4
5
6
7
8
9
10
11
12
#--------------------
# True ATE, ATT, ATU
#--------------------
def get_true_effect(df):
    stats_df = df.groupby('D')[['y0', 'y1']].mean().reset_index(drop=True)
    stats_df = pd.concat([stats_df, 
                          pd.DataFrame(df.loc[:, ['y0', 'y1']].mean(axis=0)).T], 
                          axis=0).set_index(pd.Index(['ATU', 'ATT', 'ATE']))
    stats_df['effect'] = stats_df['y1'] - stats_df['y0']
    return stats_df

get_true_effect(df)
y0 y1 effect
ATU -0.006425 1.248268 1.254693
ATT -0.005599 0.578174 0.583773
ATE -0.006097 0.981503 0.987600

次に, PSMによって効果を推定してみます.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def estimate_effect(df):
    y0_treated_weight = ((1 - df['D']) * df['prob']) / (1 - df['prob'])
    y1_untreated_weight = (df['D']) * (1 - df['prob']) / df['prob']
    y1_ate_weight = df['D'] / df['prob']
    y0_ate_weight = (1 - df['D'])/(1 - df['prob'])

    y0_untreated, y1_treated = df.groupby('D')['observed'].mean().values
    y0_treated = np.sum(y0_treated_weight * df['observed']) / np.sum(y0_treated_weight)
    y1_untreated = np.sum(y1_untreated_weight * df['observed']) / np.sum(y1_untreated_weight)
    
    y1_ate = np.sum(y1_ate_weight * df['observed'])/ np.sum(y1_ate_weight)
    y0_ate = np.sum(y0_ate_weight * df['observed'])/ np.sum(y0_ate_weight)

    res_df = pd.DataFrame({'y0':[y0_untreated, y0_treated, y0_ate],
                           'y1':[y1_untreated, y1_treated, y1_ate]})
    res_df = res_df.set_index(pd.Index(['ATU', 'ATT', 'ATE']))
    res_df['effect'] = res_df['y1'] - res_df['y0']

    return res_dfHeterogeneityの存在


estimate_effect(df)
y0 y1 effect
ATU -0.006425 1.047781 1.054207
ATT -0.006641 0.578174 0.584815
ATE -0.006512 0.858955 0.865467

ATUとATEが結構ぶれています. これがたまたまの結果なのか, 推定量のバイアスがあるかは まだ判断できないのでシミュレーションで確かめて見る必要があります

シミュレーションでバイアスがあるかの確認

1
2
3
4
5
6
7
8
9
10
res_true = []
res_estimates = []

for i in range(1000):
    tmp = dgp([2, 8, -8])
    res_true.append(get_true_effect(tmp).loc['ATE', 'effect'])
    res_estimates.append(estimate_effect(tmp).loc['ATE', 'effect'])

compare_df = pd.DataFrame({'true':res_true, 'estimate':res_estimates})
compare_df.describe()
true estimate
count 1000.000000 1000.000000
mean 1.001301 1.000366
std 0.057647 0.084449
min 0.825200 0.766833
25% 0.963600 0.945542
50% 1.000700 1.002053
75% 1.039250 1.056441
max 1.176400 1.262194
  • standard errorの大きさと比べてもPSMのバイアスはそこまで大きいものではない
  • 上で見えたバイアスらしきものはたまたま乱数の結果発生したものを考えることができる

Propensity scoreで条件づけたHeterogeneityの推定

1
2
3
hetero_df = df.groupby('prob')[['y0', 'y1']].mean()
hetero_df['effect'] = hetero_df['y1'] - hetero_df['y0']
hetero_df
y0 y1 effect
prob
0.3 -0.000718 1.999282 2.000000
0.5 -0.011445 -0.030592 -0.019146

prob == 0.3は問題設定上, TrueのCATEと対応する関係だったのでうまく推定できていますが, prob == 0.5は2つの属性に分割されており, それらCATEの平均の値が計算結果として出力されています. そのため, Heterogeneityがあるのはわかりますが, Heterogeneityの背景にあるメカニズムを示唆するような内容にはなっていません.

REMARKS

  • propensity scoreで条件づけたCATEが異なっている場合はHeterogeneityの存在を示唆するが, 正しく推定できるとは限らない
  • propensity scoreで条件づけたCATEが似通っているとしてもHeterogeneityの存在がないとは限らない
  • Heterogeneityがある場合, ATEが効果がないように見えてしまうケースもある

Follow up Question

Question

  • 会社Aは複数の事業所に分かれており, 事業所単位でスキルアップクラスを提供したりしていなかったりする
  • 事業所がスキルアップクラスを提供するかどうかは完全にrandomに定まっているとする

このとき, このrandom assignment変数をpropensity scoreに組み込んだとき, 推定量はどのような影響を受けるか?

このときの答えは

  • Nothing (in expectation) to the effect
  • standard errorsは増加する

となります. これを考えてみましょう.

またこのときトライすべきこととしては

  • ITT(=クラス受講ではなくてクラス提供の効果)を推定する
  • IVでクラス受講効果を推定する(perfect complianceがあるわけではないと思われるので)

References



Share Buttons
Share on:

Feature Tags
Leave a Comment
(注意:GitHub Accountが必要となります)