Slide 1

Slide 1 text

相関データと サンプルサイズ設計 デルタ法のサンプルサイズ設計には気をつけて statditto 2024-10-19

Slide 2

Slide 2 text

自己紹介 X: 社会人2年目 R歴は4年くらい @st4tditt0 kawaii

Slide 3

Slide 3 text

今日話すこと 相関データのA/Bテスト デルタ法を用いた仮説検定 デルタ法のサンプルサイズ設計 まとめ 相関データは適切な手法で対処すべき デルタ法を用いる際には、サンプルサイズ設計もデルタ 法に適したものを選択すべき 相関を無視すると、意図せず誤った結論が導かれる恐 れがある

Slide 4

Slide 4 text

話さないこと 細かい理論の話 気になる方は参考文献からどうぞ!

Slide 5

Slide 5 text

相関データのA/Bテスト

Slide 6

Slide 6 text

A/Bテスト 異なる実験群(Control, Treat)を比較し、その 効果を測定する実験手法 ユーザーを無作為に割り当てることが多い 次のA/Bテストを例に考える 概要:あるWebサイトのコンテンツを新しい ものに入れ替える施策 指標:CTR(総click数/総impression数) Webページにおけるユーザーの行動ログ 最もシンプルなA/Bテストの例(かば本 p6) 1

Slide 7

Slide 7 text

... データ例 dt:日付 user_id:ユーザーid impressions:コンテンツのimpression数 clicks:コンテンツのclick数 dt user_id impressions clicks 2024-09-02 1 78 10 2024-09-03 1 36 6 2024-09-05 1 53 8 2024-09-08 1 53 7 2024-09-13 1 31 5 2024-09-01 2 80 19 2024-09-07 2 50 7 1-7 of 60 rows Next 1 2 9 Previous

Slide 8

Slide 8 text

AIに聞いてみる 聞いてみた

Slide 9

Slide 9 text

サンプルサイズ設計 有意水準0.05、検出力0.80の両側検定として設計 必要なimpression数は各群33275件 各群で必要なユーザー数を計算 過去のデータでは、1ユーザーあたりの平均impression数は353.5件らしい [必要impression数]/[平均impression数]=33275/353.5=95人 power.prop.test(p1 = 0.30, # C群のCTR(過去のデータから30%とわかっている) 1 p2 = 0.31, # T群のCTR(1%ptの効果量を仮定) 2 sig.level = 0.05, # 有意水準α(真に差がない時に誤って帰無仮説を棄却してしまう割合) 3 power = 0.8) # 検出力β(真に差がある時に正しく差を検出できる割合) 4 Two-sample comparison of proportions power calculation n = 33274.15 p1 = 0.3 p2 = 0.31 sig.level = 0.05 power = 0.8 alternative = two.sided NOTE: n is number in *each* group

Slide 10

Slide 10 text

A/Aテスト 同質なC群とT群を用意して、A/Aテストを行ってみる 同質な2群の差を検定しているため有意差は出ないはず! A/Aテストのイメージ 2

Slide 11

Slide 11 text

A/Aテストをやってみる A/Aテスト用のデータ group imp click CTR C_1 34606 10370 0.30 C_2 35097 9952 0.28 有意差が出た の設計なので偶然5%を引いてしまったか……? control <- get_control_data(95) %>% 1 summarise(imp = sum(impressions), 2 click = sum(clicks)) 3 treat <- get_control_data(95) %>% 4 summarise(imp = sum(impressions), 5 click = sum(clicks)) 6 aa <- bind_rows(control,treat) %>% 7 mutate(group = c("C_1", "C_2")) %>% 8 select(group, imp, click) %>% 9 mutate(CTR = click/imp) 10 2-sample test for equality of proportions with continuity correction data: aa$click out of aa$imp X-squared = 21.795, df = 1, p-value = 3.034e-06 alternative hypothesis: two.sided 95 percent confidence interval: 0.009325615 0.022878424 sample estimates: prop 1 prop 2 0.299659 0.283557 α = 0.05

Slide 12

Slide 12 text

たくさんやってみる 何度もA/Aテストをやってみる 正しくテスト設計ができていれば、p値は一様分布になる3 simulate_test <- function(i) { 1 control <- get_control_data(95) %>% 2 summarise(imp = sum(impressions), 3 click = sum(clicks)) 4 treat <- get_control_data(95) %>% 5 summarise(imp = sum(impressions), 6 click = sum(clicks)) 7 tmp <- bind_rows(control, treat) 8 tmp <- prop.test(n = tmp$imp, x = tmp$cl 9 tmp$p.value 10 } 11 12 p_values <- future_map_dbl(1:1000, 13 simulate_test, 14 .options = furr 15 ,.progress = TR 16

Slide 13

Slide 13 text

どうして……? 今回の例ではユーザー単位でランダム化を行った 分析対象の指標はimpression単位 ランダム化単位と分析単位が異なる時は注意が必要 今回利用した検定は標本にi.i.d.を仮定している 実際は同一ユーザーの試行は相関がある(ことがある) →仮定が満たされない状況下で検定してしまった 手法が必要とする仮定を満たさない状況下では誤った結論を導く可能性がある

Slide 14

Slide 14 text

相関データへの対処

Slide 15

Slide 15 text

相関データに対する議論 実は割と有名問題 ブログや書籍、論文もたくさんある デルタ法 – 、bootstrap法、クラスターA/Bテスト など 今回はデルタ法を紹介 4 7 8

Slide 16

Slide 16 text

数式で書き直す(苦しい) 1. ユーザーと観測データ ユーザー数: 各ユーザー のimpression数: clickの有無: ( ) 2. 指標の再定義 平均値: ここで、 3. 各パラメータ click数の期待値: impression数の期待値: click数の分散: impression数の分散: click数とimpression数の共分散: k i Ni Xij i = 1, … , k; j = 1, … , Ni ¯ X = ∑i,j Xij ∑i Ni = ∑i Si/k ∑i Ni/k = ¯ S ¯ N Si = ∑j Xij μS = E(Si) μN = E(Ni) σ2 S = Var(Si) σ2 N = Var(Ni) σSN = Cov(Si, Ni)

Slide 17

Slide 17 text

デルタ法 指標に注目: は極限では多変量正規分布に従うとみなせる それらの比 が正規分布に従うことが知られている(デルタ法) デルタ法で推定された分散 導出にはテーラー展開を用いるが、ここでは省略(こちらのブログが丁寧 ) 推定した分散を用いて検定 ¯ X = ∑i,j Xij ∑i Ni = ∑i Si/k ∑i Ni/k = ¯ S ¯ N ¯ S, ¯ N ¯ X Var ( ¯ S ¯ N ) ≈ 1 kμ2 N (σ2 S − 2 μS μN σSN + μ2 S μ2 N σ2 N ) 9

Slide 18

Slide 18 text

Rによる実装 var_delta <- function(x, y){ 1 mean_x <- mean(x) 2 mean_y <- mean(y) 3 var_x <- var(x) 4 var_y <- var(y) 5 cov_xy <- cov(x, y) 6 result <- (var_x / mean_x**2 + var_y / mean_y**2 - 2 * cov_xy / 7 (mean_x * mean_y)) * (mean_x * mean_x) / (mean_y * mean_y * length(x)) 8 return(result) 9 } 10 11 delta_test <- function(mean_x, mean_y, var_x, var_y){ 12 diff = mean_y - mean_x 13 var = var_x + var_y 14 z = diff / sqrt(var) 15 p_val <- 2 * pnorm(abs(z), lower.tail = FALSE) 16 17 result <- data.frame(difference = diff, p_value = p_val) 18 return(result) 19 } 20

Slide 19

Slide 19 text

Re:たくさんやってみる(A/A) simulate_test <- function(i) { 1 control <- get_control_data(95) %>% 2 summarise(imp = sum(impressions), 3 click = sum(clicks), 4 .by = user_id) 5 treat <- get_control_data(95) %>% 6 summarise(imp = sum(impressions), 7 click = sum(clicks), 8 .by = user_id) 9 mean_c <- sum(control$click)/sum(control 10 mean_t <- sum(treat$click)/sum(treat$imp 11 var_c <- var_delta(control$click, contro 12 var_t <- var_delta(treat$click, treat$im 13 tmp <- delta_test(mean_c, mean_t, var_c, 14 tmp$p_value 15 } 16 17 p_values_aa <- future_map_dbl(1:1000, 18 simulate_test, 19 .options = furr 20 ,.progress = TR 21 概ね一様分布していそうに見える 少なくともさっきよりはマシ

Slide 20

Slide 20 text

Re:たくさんやってみる(A/B) simulate_test <- function(i) { 1 control <- get_control_data(95) %>% 2 summarise(imp = sum(impressions), 3 click = sum(clicks), 4 .by = user_id) 5 treat <- get_treat_data(95) %>% 6 summarise(imp = sum(impressions), 7 click = sum(clicks), 8 .by = user_id) 9 mean_c <- sum(control$click)/sum(control 10 mean_t <- sum(treat$click)/sum(treat$imp 11 var_c <- var_delta(control$click, contro 12 var_t <- var_delta(treat$click, treat$im 13 tmp <- delta_test(mean_c, mean_t, var_c, 14 tmp$p_value 15 } 16 17 p_values_ab <- future_map_dbl(1:1000, 18 simulate_test, 19 .options = furr 20 ,.progress = TR 21 となる試行はたったの8.2%し かない 検出力80%で設計しているのにどうし てこんなことに p < 0.05

Slide 21

Slide 21 text

デルタ法のサンプルサ イズ設計

Slide 22

Slide 22 text

何がダメだったか 通常のA/Bテストで設計したサンプルサイズでは検出力が大幅に不足してしまう 過小評価された分散を設計に用いているから デルタ法で推定した分散をサンプルサイズ設計でも利用すべき 通常のサンプルサイズ設計の式: であることを利用して、代入し整理する 10 n = 2σ2 ⋅ (z1−α/2 + z1−β)/δ2 Var( ¯ X) = σ2/n k = 2h ・ (z1− α 2 + z1−β)/δ2 , ただし, h = 1 μ2 N (σ2 S − 2 μS μN σSN + μ2 S μ2 N σ2 N )

Slide 23

Slide 23 text

Rによる実装 この関数でサンプルサイズ設計をやり直すと3427人必要だとわかる 通常の設計で求められた95人の36.4倍! 実は全くサンプルサイズが足りていなかった delta_samplesize_estimation <- function(alpha, beta, effect, h){ 1 z_1_alpha <- qnorm(1 - alpha/2) 2 z_1_beta <- qnorm(1-beta) 3 4 k <- 2*h*(z_1_alpha+z_1_beta)^2/effect^2 5 return(k) 6 } 7

Slide 24

Slide 24 text

Re:Re:今度こそ simulate_test <- function(i) { 1 control <- get_control_data(3427) %>% 2 summarise(imp = sum(impressions), 3 click = sum(clicks), 4 .by = user_id) 5 treat <- get_treat_data(3427) %>% 6 summarise(imp = sum(impressions), 7 click = sum(clicks), 8 .by = user_id) 9 mean_c <- sum(control$click)/sum(control 10 mean_t <- sum(treat$click)/sum(treat$imp 11 var_c <- var_delta(control$click, contro 12 var_t <- var_delta(treat$click, treat$im 13 tmp <- delta_test(mean_c, mean_t, var_c, 14 tmp$p_value 15 } 16 17 p_values_ok <- future_map_dbl(1:200, 18 simulate_test, 19 .options = furr 20 ,.progress = TR 21 となる試行は78% やったね! p < 0.05

Slide 25

Slide 25 text

実用上の注意点(特にWebの世界) サンプルサイズ設計の式をもう一度 実験期間の変更に応じて平均、分散、共分散も変化してしまう 実務的には次のフローで行うと良さそう 1. 実験期間の候補を定める(e.g. 1 week or 2 week) 2. 効果量の候補を定める( ) 3. 実験期間ごとに平均、分散、共分散を求める 4. を計算(e.g. h_1week, h_2week) 5. の組み合わせごとにサンプルサイズを求める 6. どの設定で実施するか考える h = 1 μ2 N (σ2 S − 2 μS μN σSN + μ2 S μ2 N σ2 N ) δ = {0.01, 0.05} h δ, h

Slide 26

Slide 26 text

まとめ

Slide 27

Slide 27 text

デルタホウカンゼンニリカイシタ 相関データには気をつけろ! デルタ法は便利だけど正しく使わないと危ないぞ! A/Bテストを正しくやるのは難しい;; 手法が必要とする仮定を意識して利用したい

Slide 28

Slide 28 text

Enjoy!

Slide 29

Slide 29 text

データ生成過程 独立な試行ではあるが同一でない分布を仮定していた 1. ユーザーID ユーザー数 に対して、ユーザーIDは 2. 各ユーザーの真のCTR 3. impressionとclick 各日付に対して、impressionが発生するかどうかをサンプル 発生した場合 k 1, 2, … , k pi ∼ Beta(3.0, 7.0) is_impressioni ∼ Bernoulli(0.5) Ni ∼ Uniform(1, 100) Si ∼ Binomial(is_impressioni, pi)

Slide 30

Slide 30 text

1. 2. 3. 4. 5. 6. 7. 8. Reference Ron K, Diane T, Ya X. A/Bテスト実践ガイド. アスキードワンゴ; 2021. Kohavi R, Longbotham R, Sommerfield D, Henne RM. Controlled experiments on the web: Survey and practical guide. Data Min Knowl Discov. 2009;18(1):140-181. doi: gota morishita. なぜAAテストにおけるp値は一様分布になるのか?. 2021. Deng A, Knoblich U, Lu J. Applying the delta method in metric analytics: A practical guide with novel ideas. In: Proceedings of the 24th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining. KDD ’18. Association for Computing Machinery; 2018:233-242. doi: Taro T. 統計指標の信頼区間を評価する delta method とその応用(論文紹介). 2018. 中村. 検索エンジンのABテストで発生するユーザー内相関を突破する. 2021. 伊藤, 藤田. なぜあなたのA/Bテストはうまくいくのか?a/Bテストの分析で注 意すること. 2021. 伊藤寛武, 金子雄祐. Pythonで学ぶ効果検証入門. オーム社; 2024. 10.1007/s10618-008-0114-1 https://zenn.dev/morishita/articles/3c77d00b303c76 10.1145/3219819.3219919 https://engineering.linecorp.com/ja/blog/delta-method https://www.m3tech.blog/entry/search-ab https://developers.cyberagent.co.jp/blog/archives/33310/

Slide 31

Slide 31 text

9. 10. sz_dr. 確率変数の比の分布における平均と分散をデルタ法で求める. 2018. Zhou J, Lu J, Shallah A. All about sample-size calculations for a/b testing: Novel extensions & practical guide. In: Proceedings of the 32nd ACM International Conference on Information and Knowledge Management. CIKM ’23. Association for Computing Machinery; 2023:3574-3583. doi: https://www.szdrblog.info/entry/2018/11/18/154952 10.1145/3583780.3614779