安井翔太著『効果検証入門』を読了しました。
因果推論や統計の基礎を学ぶ上でとても良い本でしたが、同時に作者のRコードもかなり洗練されていてRの勉強にもなりました。そこで今回は書籍で紹介されているコードの中からとくにエレガントだと思った箇所を5か所ピックアップしました。
コード全文はここにあります
第5位:エラーバーのプロット
ggplot2でエラーバーをプロットするのは地味に面倒だが、お手本のようなコードなので、このままコピペして使える
using_voucher_results %>%
ggplot(aes(y = estimate, x = model_index)) +
geom_point() +
geom_errorbar(aes(ymax = estimate + std.error*1.96,
ymin = estimate - std.error*1.96,
width = 0.1)) +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
plot.title = element_text(hjust = 0.5),
legend.position = "bottom",
plot.margin = margin(0.5,1,0.5,1, "cm"))
第4位:回帰分析への神パイプライン
data → 回帰モデル → broom:tidy() という華麗なるパス
ong_coef <- biased_data %>%
lm(data = .,
formula = spend ~ treatment + recency + channel + history) %>%
tidy()
summary ではなく tidy() を使うことで結果をデータフレーム化することができ、パラメータの取り出しが容易になる
## aの結果から介入効果に関するパラメーターのみを取り出す
alpha_1 <- short_coef %>%
filter(term == "treatment") %>%
pull(estimate)
第3位: pull の利用
pull
関数はデータフレームの特定のカラムをベクトルとして取り出す関数
select
と似ているが、pull
の場合はベクトルなので検定モデルに入れやすい
# (6) t検定を行う
## (a)男性向けメールが配信されたグループの購買データを得る
mens_mail <- male_df %>%
filter(treatment == 1) %>%
pull(spend)
## (b)メールが配信されなかったグループの購買データを得る
no_mail <- male_df %>%
filter(treatment == 0) %>%
pull(spend)
## (a)(b)の平均の差に対して有意差検定を実行する
rct_ttest <- t.test(mens_mail, no_mail, var.equal = T)
第2位:回帰分析の自動化
複数のモデルをbroom
パッケージを使って効率的に回す
## モデル式のベクトルを用意
formula_vec <- c(spend ~ treatment + recency + channel, # モデルA
spend ~ treatment + recency + channel + history, # モデルB
history ~ treatment + channel + recency) # モデルC
## formulaに名前を付ける
names(formula_vec) <- paste("reg", LETTERS[1:3], sep ="_")
## モデル式のデータフレーム化
models = formula_vec %>%
enframe(name = "model_index", value = "formula")
## まとめて回帰分析を実行
df_models <- models %>%
mutate(model = map(.x = formula, .f = lm, data = biased_data)) %>%
mutate(lm_result = map(.x = model, .f = tidy))
enframe
関数が良い味出してます
第1位:バイアスのあるデータの作成
こんな方法があるなんて…
obs_rate_c <- 0.5
obs_rate_t <- 0.5
## バイアスのあるデータを作成
biased_data <- male_df %>%
mutate(obs_rate_c =
ifelse( (history > 300) | (recency < 6) |
(channel == "Multichannel"), obs_rate_c, 1),
obs_rate_t =
ifelse( (history > 300) | (recency < 6) |
(channel == "Multichannel"), 1, obs_rate_t),
random_number = runif(n = NROW(male_df))) %>%
filter( (treatment == 0 & random_number < obs_rate_c ) |
(treatment == 1 & random_number < obs_rate_t) )
サンプルの値に基づいて、閾値をルールベースで決める→一様乱数をmutate
で作成→閾値とrandom_number を比べてfilteringという方法
どうやって思いつくんだろう