傾向スコアを用いた逆確率重み付け法(IPTW)

本投稿は、以下の本の実装例を学習用に写経したものになります。詳細について気になりましたら、本を読んでみてください。

つくりながら学ぶ! Pythonによる因果分析 ~因果推論・因果探索の実践入門 (Compass Data Science)
つくりながら学ぶ! Pythonによる因果分析 ~因果推論・因果探索の実践入門 (Compass Data Science)

実装例は筆者らのgithubに公開されています。

GitHub - YutaroOgawa/causal_book: 書籍「作りながら学ぶ! PyTorchによる因果推論・因果探索」の実装コードのリポジトリです
書籍「作りながら学ぶ! PyTorchによる因果推論・因果探索」の実装コードのリポジトリです. Contribute to YutaroOgawa/causal_book development by creating an account on GitHub.

 

ライブラリインポート
# 乱数のシードを設定
import random
import numpy as np

np.random.seed(1234)
random.seed(1234)

# 使用するパッケージ(ライブラリと関数)を定義
# 標準正規分布の生成用
from numpy.random import *

# グラフの描画用
import matplotlib.pyplot as plt

# SciPy 平均0、分散1に正規化(標準化)関数
import scipy.stats

# シグモイド関数をimport
from scipy.special import expit

# その他
import pandas as pd
データ作成
# データ数
num_data = 200

# 年齢
x_1 = randint(15, 76, num_data)  # 15から75歳の一様乱数

# 性別(0を女性、1を男性とします)
x_2 = randint(0, 2, num_data)  # 0か1の乱数


# x_1, x_2に依存する変数Zを作成する
# ノイズの生成
e_z = randn(num_data)

# シグモイド関数に入れる部分
z_base = x_1 + (1-x_2)*15 - 40 + 5*e_z

# シグモイド関数を計算
z_prob = expit(0.1*z_base)

# テレビCMを見たかどうかの変数(0は見ていない、1は見た)
Z = np.array([])

for i in range(num_data):
    Z_i = np.random.choice(2, size=1, p=[1-z_prob[i], z_prob[i]])[0]
    Z = np.append(Z, Z_i)


# 購入量Yを作成
# ノイズの生成
e_y = randn(num_data)

Y = -x_1 + 20*x_2 + 15*Z + 80 + 10*e_y


# データフレームにまとめる
df = pd.DataFrame({'年齢': x_1,
                   '性別': x_2,
                   'CMを見た': Z,
                   '購入量': Y,
                   })


# 平均値を確認
print('CMを見たデータ')
print(df[df["CMを見た"] == 1.0].mean())
print("--------")
print('CMを見てないデータ')
print(df[df["CMを見た"] == 0.0].mean())
CMを見たデータ
年齢       54.968750
性別        0.460938
CMを見た     1.000000
購入量      50.485554
dtype: float64
--------
CMを見てないデータ
年齢       31.708333
性別        0.750000
CMを見た     0.000000
購入量      63.071757
dtype: float64
傾向スコアの推定
# scikit-learnからロジスティク回帰をimport
from sklearn.linear_model import LogisticRegression

# 説明変数
X = df[["年齢", "性別"]]

# 被説明変数(目的変数)
Z = df["CMを見た"]

# 回帰の実施
reg = LogisticRegression().fit(X,Z)

# 回帰した結果の係数を出力
print("係数beta:", reg.coef_)
print("係数alpha:", reg.intercept_)
係数beta: [[ 0.10797803 -1.90183645]]
係数alpha: [-2.92565399]
各人の傾向スコアを求める
Z_pre = reg.predict_proba(X)
print('傾向スコア')
print(Z_pre[0:5])  # 5人ほどの結果を見てみる
print("----")
print('CMを見たかの正解')
print(Z[0:5])  # 5人ほどの正解
傾向スコア
[[0.02255503 0.97744497]
 [0.32178103 0.67821897]
 [0.29000804 0.70999196]
 [0.07481223 0.92518777]
 [0.87125306 0.12874694]]
----
CMを見たかの正解
0    1.0
1    1.0
2    1.0
3    1.0
4    0.0
Name: CMを見た, dtype: float64
平均処置効果ATEを求める
ATE_i = Y/Z_pre[:, 1]*Z - Y/Z_pre[:, 0]*(1-Z)
ATE = 1/len(Y)*ATE_i.sum()
print("推定したATE", ATE)
推定したATE: 16.378782114604427

コメント

タイトルとURLをコピーしました