効果検証入門をPythonで実装する：第1章RCT（前編）

何番煎じかわかりませんが、「効果検証入門 正しい比較のための因果推論／計量経済学の基礎」安井翔太著、株式会社ホクソエム監修をPythonで実装していきます。
この記事では該当書籍の第1章を扱います。
初学者なので記事内容に不備、不正確な点あればコメントいただけると幸いです。


##RCTとはなにか
RCTとはRandomised Controlled Trialの略であり、介入をする（施策を打つ）ユーザ郡を完全にランダムに選択したうえで実験をし、介入があった郡となかった郡の差分を分析することで介入の効果を検証する手法です。
RCTではランダムにユーザが選ばれるため、セレクションバイアスが生じにくく介入そのものの効果をより正確に検証することが可能です。
ちなみに、[2019年のノーベル経済学賞は「世界の貧困削減に向けたフィールド実験」](https://www.nobelprize.org/prizes/economic-sciences/2019/press-release/)に対して与えられましたが、ここでいうフィールド実験がRCTの手法を用いてなされました。



##状況設定
さっそく実装へ写っていきたいと思います。
ここでは、このRCTについてあるECサイトのメール配信が例に取られています。
あるECサイトでランダムにメール配信（女性向け・男性向け・配信なし）を行った際、このメールの購買金額への影響はあったのか？というのを検証していきます。


##データセットについて
本文で使われているデータセット[MineThatData E-Mail Analytics And Data Mining Challenge dataset](https://blog.minethatdata.com/2008/03/minethatdata-e-mail-analytics-and-data.html)を使用しています。
『このデータセットは、ECサイトのユーザに足していRCTを適用したメールマーケティングを行ったものです。』とのことです。

##環境について
- OS：Windows10
- Python：Python 3.8.5（Anaconda使っています）
- エディタ：VSCode  
jupyter notebookみたいにも使えて便利ですね。

##データの読み込み
```Python
import requests
import io
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
import scipy.stats as stats


url = 'http://www.minethatdata.com/Kevin_Hillstrom_MineThatData_E-MailAnalytics_DataMiningChallenge_2008.03.20.csv'
res = requests.get(url).content
df: pd.DataFrame = pd.read_csv(io.StringIO(res.decode('utf-8')), header=0)
```
（VSCodeで書いており、予測変換機能の都合からdfを生成するときに[型ヒント](https://docs.python.org/3/library/typing.html#generics)を利用しています。）



##データの確認
まずは検証をする前にデータの中身の確認をしていきます。

#### 全体を見る

```Python
df

>>>
	recency	history_segment	history	mens	womens	zip_code	newbie	channel	segment	visit	conversion	spend
0	10	2) $100 - $200	142.44	1	0	Surburban	0	Phone	Womens E-Mail	0	0	0.0
1	6	3) $200 - $350	329.08	1	1	Rural	1	Web	No E-Mail	0	0	0.0
2	7	2) $100 - $200	180.65	0	1	Surburban	1	Web	Womens E-Mail	0	0	0.0
3	9	5) $500 - $750	675.83	1	0	Rural	1	Web	Mens E-Mail	0	0	0.0
4	2	1) $0 - $100	45.34	1	0	Urban	0	Web	Womens E-Mail	0	0	0.0
...	...	...	...	...	...	...	...	...	...	...	...	...
63995	10	2) $100 - $200	105.54	1	0	Urban	0	Web	Mens E-Mail	0	0	0.0
63996	5	1) $0 - $100	38.91	0	1	Urban	1	Phone	Mens E-Mail	0	0	0.0
63997	6	1) $0 - $100	29.99	1	0	Urban	1	Phone	Mens E-Mail	0	0	0.0
63998	1	5) $500 - $750	552.94	1	0	Surburban	1	Multichannel	Womens E-Mail	0	0	0.0
63999	1	4) $350 - $500	472.82	0	1	Surburban	0	Web	Mens E-Mail	0	0	0.0
64000 rows × 12 columns
```
64000件のデータと12個の項目を持つデータであることがわかりました。

####データ型の確認
```Python
df.dtypes
>>>
recency              int64
history_segment     object
history            float64
mens                 int64
womens               int64
zip_code            object
newbie               int64
channel             object
segment             object
visit                int64
conversion           int64
spend              float64
dtype: object
```

####様々な値の集計
```Python
df.describe().round(2)
>>>
	recency	history	mens	womens	newbie	visit	conversion	spend
count	64000.00	64000.00	64000.00	64000.00	64000.0	64000.00	64000.00	64000.00
mean	5.76	242.09	0.55	0.55	0.5	0.15	0.01	1.05
std	3.51	256.16	0.50	0.50	0.5	0.35	0.09	15.04
min	1.00	29.99	0.00	0.00	0.0	0.00	0.00	0.00
25%	2.00	64.66	0.00	0.00	0.0	0.00	0.00	0.00
50%	6.00	158.11	1.00	1.00	1.0	0.00	0.00	0.00
75%	9.00	325.66	1.00	1.00	1.0	0.00	0.00	0.00
max	12.00	3345.93	1.00	1.00	1.0	1.00	1.00	499.00

df.corr()
>>>
	recency	history	mens	womens	newbie	visit	conversion	spend
recency	1.000000	-0.246591	-0.031336	-0.026617	-0.052106	-0.074765	-0.024412	-0.016348
history	-0.246591	1.000000	0.112677	0.114685	0.223279	0.065153	0.029405	0.021729
mens	-0.031336	0.112677	1.000000	-0.816943	0.020900	0.006712	0.002492	0.008599
womens	-0.026617	0.114685	-0.816943	1.000000	0.021346	0.051999	0.012702	0.002173
newbie	-0.052106	0.223279	0.020900	0.021346	1.000000	-0.073924	-0.011331	-0.007623
visit	-0.074765	0.065153	0.006712	0.051999	-0.073924	1.000000	0.230165	0.168507
conversion	-0.024412	0.029405	0.002492	0.012702	-0.011331	0.230165	1.000000	0.732114
spend	-0.016348	0.021729	0.008599	0.002173	-0.007623	0.168507	0.732114	1.000000
```
データ数は64000件、最終購入月からの平均経過月数は5.76ヶ月、昨年の購入学の平均は$242、平均購入金額は$1.05などといったことがわかりました。
相関係数を見るとSpendとConversionの相関係数が最も高く0.73となっています。その他の相関係数はほとんどが0.1を切っているような状況です。

##男性向けメールの効果検証
男性向けメールの検証のため、男性向けメール受信者とメール非受信者のデータを抽出します。

```Python
df2: pd.DataFrame = df[df.segment != 'Womens E-Mail']
df2['treatment'] = np.where(df2['segment'] == 'Mens E-Mail', 1, 0)

df_mens = df2[df2['treatment']==1]
df_nomail = df2[df2['treatment']==0]
```
ここで作ったdf_mensの群とdf_nomailの群の購入金額に有意差があるかを検証します。検定を実施する前に一度、データを確認します。

```Python
df_mens.describe()

>>>
	recency	history	mens	womens	newbie	visit	conversion	spend	treatment
count	21307.000000	21307.000000	21307.000000	21307.000000	21307.000000	21307.000000	21307.000000	21307.000000	21307.0
mean	5.773642	242.835931	0.550946	0.551415	0.501525	0.182757	0.012531	1.422617	1.0
std	3.513350	260.355685	0.497409	0.497361	0.500009	0.386476	0.111241	17.754205	0.0
min	1.000000	29.990000	0.000000	0.000000	0.000000	0.000000	0.000000	0.000000	1.0
25%	2.000000	63.580000	0.000000	0.000000	0.000000	0.000000	0.000000	0.000000	1.0
50%	6.000000	157.220000	1.000000	1.000000	1.000000	0.000000	0.000000	0.000000	1.0
75%	9.000000	325.215000	1.000000	1.000000	1.000000	0.000000	0.000000	0.000000	1.0
max	12.000000	3215.970000	1.000000	1.000000	1.000000	1.000000	1.000000	499.000000	1.0
```

```Python
df_nomail.describe()
>>>
	recency	history	mens	womens	newbie	visit	conversion	spend	treatment
count	21306.000000	21306.000000	21306.000000	21306.000000	21306.000000	21306.000000	21306.000000	21306.000000	21306.0
mean	5.749695	240.882653	0.553224	0.547639	0.501971	0.106167	0.005726	0.652789	0.0
std	3.497517	252.739362	0.497171	0.497737	0.500008	0.308059	0.075456	11.588200	0.0
min	1.000000	29.990000	0.000000	0.000000	0.000000	0.000000	0.000000	0.000000	0.0
25%	2.000000	65.300000	0.000000	0.000000	0.000000	0.000000	0.000000	0.000000	0.0
50%	5.000000	156.655000	1.000000	1.000000	1.000000	0.000000	0.000000	0.000000	0.0
75%	9.000000	325.167500	1.000000	1.000000	1.000000	0.000000	0.000000	0.000000	0.0
max	12.000000	3345.930000	1.000000	1.000000	1.000000	1.000000	1.000000	499.000000	0.0
```

Spendの額を比較すると
男性向けメール：1.422617
配信なし：0.652789
となっており、差が生じているように見えます。

これが本当に差があるかを検定により確認していきます。

##検定
ここではt検定と呼ばれる検定手法をつかいました[^1]。Pythonではscipyのstatst.ttest_indを使うことでt検定を行うことができます。

```Python
import scipy.stats
t, p = stats.ttest_ind(df_mens.spend, df_nomail.spend, equal_var=True)
print('p-value =', p)

>>>
p-value = 1.163200872605869e-07
```
P-valueは2つの群の差が0である確率を示しており、今回のケースでは1.16e-07であり十分に小さくなっており、メール配信の効果はあったと言える結果がでています。



##まとめ
本項目ではRCTで得られた結果に対してt検定を用いて結果に有意差があったかを検証しました。


[^1]: 検定方法の選び方についてはまた別途まとめていきたいと思っています。