LoginSignup
0
0

More than 3 years have passed since last update.

効果検証入門をPythonで実装する:第1章RCT(前編)

Last updated at Posted at 2021-03-28

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

RCTとはなにか

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

状況設定

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

データセットについて

本文で使われているデータセットMineThatData E-Mail Analytics And Data Mining Challenge datasetを使用しています。
『このデータセットは、ECサイトのユーザに足していRCTを適用したメールマーケティングを行ったものです。』とのことです。

環境について

  • OS:Windows10
  • Python:Python 3.8.5(Anaconda使っています)
  • エディタ:VSCode
    jupyter notebookみたいにも使えて便利ですね。

データの読み込み

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を生成するときに型ヒントを利用しています。)

データの確認

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

全体を見る

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個の項目を持つデータであることがわかりました。

データ型の確認

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

様々な値の集計

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を切っているような状況です。

男性向けメールの効果検証

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

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の群の購入金額に有意差があるかを検証します。検定を実施する前に一度、データを確認します。

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
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検定を行うことができます。

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. 検定方法の選び方についてはまた別途まとめていきたいと思っています。  

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0