はじめに
今回は、「ChatGPTにハンズオンを作らせてみた」の第3弾で、DID(差分の差分法)を勉強しました。
第2弾はこちら↓
DID(差分の差分法)
「あるグループに何かしらの介入(政策や施策など)を実施したとき、実施しなかったグループと比べてどのくらい変化したのか?」を分析するための因果推論手法です。
処置群(介入を受けたグループ)の変化と対照群(介入を受けていないグループ)の変化の差分をとることで、DIDの推定値を算出するため、差分の差分法とも呼ばれます。
使用データ
Kaggleのデータセットにある、「Retailrocket recommender system dataset」というEコマースのレコメンデーションシステムで使用される商品プロパティの情報を記録したデータセットを用いました。その中でも、今回は次の3つの変数をピックアップして使用しました。
変数 | 説明 |
---|---|
timestamp | イベントの発生時刻(ミリ秒単位) |
event | ユーザーの行動(view 、addtocart 、transaction ) |
transactionid | 購入が発生した場合に記録される取引ID(NaNでない場合は購入) |
また、このデータを用いて、次の変数を作成しました。
変数 | 説明 |
---|---|
discounted | 割引対象かどうか(0=対象外、1=対象) |
post_discount | 割引後かどうか(0=割引前、1=割引後) |
interact | DIDの交互作用項(割引後かつ割引対象の商品) |
やること
- Eコマースのデータから、取引データ(実際に購入されたデータ)のみを抽出
- 介入するグループ(割引対象)を定義
- 介入のタイミングを定義
-
介入を受けたグループの売上の変化
と介入を受けなかったグループの売上の変化
の差分を取り、割引の効果があったかを測定
使用コード
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import statsmodels.api as sm
import seaborn as sns
# データ読み込み
df = pd.read_csv("data/Retailrocket recommender system dataset/events.csv")
# ミリ秒のUNIX時間を日付に変換
df["timestamp"] = pd.to_datetime(df["timestamp"], unit="ms")
# 日付のみに変換
df["date"] = df["timestamp"].dt.date
今回のデータは、取引データ以外も含まれているため、取引データのみを抽出します。
# 取引データのみを抽出
df_sales = df[df["event"] == "transaction"]
今回のデータでは、どの商品が割引対象かどうかが分からないので、こちら側が手動で割引対象の商品を定義します。(商品IDが10000から20000の間にある商品とします。)
# 割引を受けた商品(処置群)を定義
df_sales["discounted"] = df_sales["itemid"].apply(lambda x: 1 if 100000 <= x <= 200000 else 0)
割引が開始されたタイミングについても手動で定義していきます。(2015年7月1日を基準に設定します。)
# 割引開始日
discount_start_date = pd.to_datetime("2015-07-01").date()
# 割引前・後のフラグ
df_sales["post_discount"] = df_sales["date"].apply(lambda x: 1 if x >= discount_start_date else 0)
処置群(介入を受けたグループ)と対照群(介入を受けなかったグループ)に分けて、売上回数をカウントして、一度可視化してみます。
# 商品ごとに売上回数をカウント
df_did = df_sales.groupby(["date", "discounted", "post_discount"]).size().reset_index(name="sales")
# 割引前後の売上トレンド
sns.lineplot(data=df_did, x="date", y="sales", hue="discounted")
plt.axvline(discount_start_date, color='red', linestyle="--", label="Discount Start")
plt.legend(title="Discounted Product")
plt.xticks(rotation=45)
plt.show()
DIDでは、単純に「割引前と割引後の売上」を比較するのではなく、「通常商品の売上の変化」と「割引商品の売上の変化」を比較することが重要なため、交互作用項を追加したうえで、DIDを実装します。
# 交互作用項の作成
df_did["interact"] = df_did["discounted"] * df_did["post_discount"]
# 回帰モデルの構築
X = sm.add_constant(df_did[["post_discount", "discounted", "interact"]])
y = df_did["sales"]
model = sm.OLS(y, X).fit()
print(model.summary())
分析結果
post_discount
とdiscounted
は、それぞれ単純な「割引前後の売上比較」と「商品ごとの比較」になってしまうため、交互作用項であるinteract
のみに注目する。
- 係数: 1.11
- 割引導入後の売上の変化はほぼゼロに近い
- P値: 0.896
- 割引の影響は統計的に優位ではない(
P<0.05
であれば有意と判断)
- 割引の影響は統計的に優位ではない(
- 解釈: この結果から、割引が売上に明確な影響を与えたとは言えない
おわりに
今回は、Kaggleのデータセットから、割引対象と割引開始のタイミングを完全に手動で決めたので、有意な結果が出なくて当然かなと思います。