Upgrade to Pro — share decks privately, control downloads, hide ads and more …

相関データとサンプルサイズ設計 ~デルタ法のサンプルサイズ設計には気をつけて~

statditto
October 19, 2024
410

相関データとサンプルサイズ設計 ~デルタ法のサンプルサイズ設計には気をつけて~

Tokyo.R#115 応用セッションの登壇資料です。
Quartoで作成しているので一部pdf化の際に見切れています。完全版はこちらを参照してください。
https://statditto.com/posts/delta_test/

statditto

October 19, 2024
Tweet

Transcript

  1. ... データ例 dt:日付 user_id:ユーザーid impressions:コンテンツのimpression数 clicks:コンテンツのclick数 dt <date> user_id <chr>

    impressions <dbl> clicks <dbl> 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
  2. サンプルサイズ設計 有意水準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
  3. 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
  4. たくさんやってみる 何度も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
  5. 数式で書き直す(苦しい) 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)
  6. 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
  7. 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 概ね一様分布していそうに見える 少なくともさっきよりはマシ
  8. 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
  9. 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
  10. 実用上の注意点(特に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
  11. データ生成過程 独立な試行ではあるが同一でない分布を仮定していた 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)
  12. 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/
  13. 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