A/B Test 看到顯著也不能信?小心統計檢定力不足!

by 好豪
Published: Updated:

這篇文章要和你一起探討一個非常基本、但你會發現有很多資料科學家無法清楚回答的問題:

A/B Test 看到「顯著結果」,就代表實驗有效、應該做出改變嗎?

答案是:不見得!意外的是,你如果試著拿去路上問數據分析從業者,會有非常多人脫口而出「顯著就好啦,不然呢?」,又或者,即使他們有所猶豫、也不知道該怎麼清楚解釋哪裡有問題。

以下是個非常經典的案例,GuessTheTest 網站在 2021 年曾經分享過的 A/B 測試數據,兩種網站的設計之間,其中一種會讓連結點擊轉換率提升 337% 這麼多!

A/B 實驗網站訪客數點擊人數點擊轉換率轉換率提升
控制組(A組)82 人3 人3.7%
實驗組(B組)75 人12 人16.0%337%
本文將會反覆提到、並且跟你一起深入探討這個實驗的問題!
來源:論文 Table 1

不只是轉換率巨大差異肉眼可見,當時統計專家也算出 P 值是 0.009,明顯小於我們常用的 0.05 顯著水準;也可算出統計檢定力是 86%,高於業界常用的 80% 標準。各項數據都讓人想脫口而出:「顯著就好啦,不然呢?」。

這篇統計學筆記將回答這個基本的問題「看到 A/B Test 顯著結果,可以相信嗎?」,與你分享以上範例中的 A/B 測試結果為什麼事實上不可信,我將白話地介紹 A/B Test 專家 Ron Kohavi 的學術文章《A/B Testing Intuition Busters》 怎麼解決這個問題。本文各小節摘要如下:

  • 第 1 小節:簡介 Power Analysis,用效果量、顯著水準、以及樣本數來算出檢定力
  • 第 2 小節:雖然檢定力能算得出來,但是拿實驗結果的 P 值來算出檢定力卻是巨大的錯誤
  • 第 3 小節:要避免統計檢定力不足的方法,就是恪守實驗流程,事先就設定好樣本數、檢定力、及顯著水準,再開始 A/B 測試

文章中也會用 Python 的 statsmodels 套件示範,讓你可以親手驗算與練習。


A/B Test 的 Power Analysis

A/B Test 必須要執行 Power Analysis(統計檢定力分析)以確認實驗「夠不夠力」、能讓你獲得合理結論,「夠不夠力」所說的統計檢定力(Statistical Power)代表效果真實存在時、被統計工具檢測出來顯著的機率。檢定力同時受到效果量(Effect Size)、顯著水準、還有樣本大小影響,Power Analysis 正是在計算這幾個元素之間的關聯。

筆者好豪認為,介紹 Power Analysis 最簡單的方法是「三缺一」思考法。在假設檢定之中,效果量、樣本數、顯著水準、以及統計檢定力這四個元素,只要給定其中三個、你就有辦法透過假設檢定的數學公式算出另外一個。先別急著挖出你的數理統計課本來找公式,只要用 Python statsmodels 套件裡的 TTestIndPower.solve_power() 函式,你可以親手實驗看看這個「三缺一」思考法:(以下將重現 這個 A/B 測試樣本數計算機 網頁預設值的結果)

>>> from statsmodels.stats.power import TTestIndPower
>>> import statsmodels.api as sm

# 只缺效果量
>>> TTestIndPower().solve_power(effect_size=None, nobs1=1021, alpha=0.05, power=0.8)
0.12405506002472498

# 只缺樣本數
>>> TTestIndPower().solve_power(effect_size=0.124, nobs1=None, alpha=0.05, power=0.8)
1021.8848499760113

# 只缺顯著水準
>>> TTestIndPower().solve_power(effect_size=0.124, nobs1=1021, alpha=None, power=0.8)
0.05014205520538554

# 只缺檢定力
>>> TTestIndPower().solve_power(effect_size=0.124, nobs1=1021, alpha=0.05, power=None)
0.799659859377787
>>> # 另個函式也能達成相同目的:
>>> sm.stats.tt_ind_solve_power(effect_size=0.124, nobs1=1021, alpha=0.05)
0.799659859377787

回到 GuessTheTest 案例的設定:你已經完成了一個 A/B 測試,已搜集完資料、並看到顯著結果,我們來看看 Power Analysis 四大元素,我們有什麼、缺什麼:

  • 搜集完資料,樣本數已知
  • A/B 測試完成,表示我們算得出來 A 與 B 兩組數據的差異(效果量)
  • 既然看到顯著結果,就是用了 P 值 < 顯著水準 來判定,已經使用了 0.05 顯著水準
  • 唯一缺少的就是檢定力(Power)

所以現在我們算算看文章開頭表格的數據:

  • 樣本數:82 人與 75 人
  • 效果量:43.6%
  • 顯著水準:0.05
>>> from statsmodels.stats.proportion import proportion_effectsize
>>> TTestIndPower().solve_power(
...     effect_size=proportion_effectsize(3/82, 12/75), 
...     nobs1=82, ratio=75/82, 
...     alpha=0.05, 
...     power=None,
...     alternative='smaller')
0.8610846081980538

TTestIndPower.solve_power() 算出來檢定力是 86%,還高於所有資料科學家常用的標準 檢定力=80%,既然檢定力夠高,我們可以說這個實驗可信了嗎?很遺憾地,不行

我們將進一步聊聊為什麼不該進行「後見之明」的 Power Analysis。


A/B Test 結束後才算的統計檢定力,完全沒營養!

如果完全按照 GuessTheTest 案例的數據,TTestIndPower().solve_power 函式算出來檢定力明明是 86% 這麼高,為什麼還是不可信呢?

因為事後才算檢定力只是後見之明,看著結果數據,任誰都能不管實驗可信度、大肆硬編故事解釋數據。但嚴謹的資料科學真正需要的是先見之明

在 A/B 測試開始之前,事先控制好需要的可信度(檢定力)

337% 這個數字是看著結果的後見之明,那先見之明又是什麼數字呢?

GuessTheTest 案例中的網站目前連結點擊轉換率 3.7%,現在,請你摸著良心問問自己,你有沒有任何設計點子能讓轉換率提升到 10% 以上?有在公司工作過的你我都知道,沒人敢說自己做得到,因為轉換率光是要從 3.7% 提升到 4% 或 5% 就已經超級難了!

所以在 GuessTheTest 案例,我們要丟掉自以為每次都能提昇轉換率 337% 的「普信」,我們的先見之明應該是:「轉換率能從 3.7% 提升到 4% 就很棒了」。依此把期望的成效成長設定成較合理的 10% 相對差異,那麼,重新進行 Power Analysis 運算後,範例中實驗檢定力其實只有 6%

>>> TTestIndPower().solve_power(
...     effect_size=proportion_effectsize(3/82, 3/82*(1+0.1)), 
...     nobs1=82, 
...     alpha=0.05, 
...     power=None,
...     alternative='smaller')
0.06382418554757104

開頭範例中的 A/B 測試,實際上檢定力非常低,就算實驗真的有效、能達到 10% 的轉換率提升(H1 為真)、只有 6% 的超低機率有可能看到顯著結果。從我們實驗的低樣本數算出來檢定力 6%,代表就算新設計真的很棒,實驗也沒能力檢驗出來。

雖然實驗結果給我們 337% 的超高漲幅、又有顯著,我們現在更傾向相信,這個顯著結果只是單純運氣造成的偽陽性(False Positive)。結論出:此 A/B 測試不可信

會造成這個與直覺矛盾的不可信實驗,在於 A/B 測試前與後「理論上」都算得出來檢定力,但「實際上」有用處的只有測試前設定的檢定力:

  • 337% 漲幅算出來的檢定力,是實驗之後結果得出的後見之明,以此算出 86% 的檢定力(Post-hoc Power)對於決策毫無意義
  • 10% 成效提升才是實驗之前就能掌握的先見之明,以此算出檢定力 6% 才是符合推論邏輯的

論文 提到 A/B Test 結束之後才計算檢定力(Post-hoc Power)的主要問題是 P 值在低檢定力會更劇烈浮動。從我們前面介紹過的「三缺一」TTestIndPower 計算得知,事後要回推檢定力需要顯著水準、樣本數、與效果量,在樣本數固定時,若 P 值越低(也就是觀測到的效果量越大),檢定力的確會越強,這是 TTestIndPower 算得出來的現象。然而,「實際上」低檢定力的假設檢定,有更高機率產生出超低 P 值,低檢定力實驗很可能會產出低 P 值來「假裝」自己是高檢定力實驗,我們只用最後的低 P 值來事後回推檢定力,就會被「實際上」低檢定力實驗給欺騙、以為它是高檢定力。

因此,當資料科學家討論統計檢定力,只有在假設檢定開始之前設定的檢定力才有意義,而假設檢定結束、得到 P 值後才回頭算出來的檢定力,毫無營養、沒有解讀價值!這稱為「檢定力悖論」(Power Approach Paradox),假設有兩個 A/B 測試都看到顯著結果,計算後發現實驗一回推出的檢定力比實驗二高,依照檢定力的定義、我們會誤以為實驗一更可信。依照這個小節的論述,這個實驗一「更可信」的推論是錯誤的,因為事後回推的檢定力沒有解讀價值。

總之,只要你看到任何 A/B 測試分析,不是在實驗開始前先決定好檢定力,而是實驗結束後才依照 P 值推算出檢定力,這完全是誤用檢定力。再用 GuessTheTest 案例的數據囉唆釐清一次:

  • 用 337% 漲幅以及 P 值是測試結束後得出的後見之明,算出來檢定力 86% 沒有意義、不該採用
  • 用實驗開始前就能預期的 10% 合理漲幅,推算出來 6% 檢定力,這才值得參考

現在我們理解誤用檢定力、造成實驗檢定力不足的問題,而要避免誤用檢定力其實非常簡單,下個小節我們接著討論。


怎麼解決統計檢定力不足的 A/B Test?

研究 指出,當 A/B 測試的統計檢定力過低、小於 10% 的時候,有高達 50% 的機率實驗會給出相反的效果。GuessTheTest 案例在檢定力只有 6% 時看到 337% 成長的正面效果,有將近一半的可能,真相是新設計會帶來負面效果。

Kohavi 的 論文 中也指出另一個少被提及的問題:低檢定力的顯著結果,有更高的可能性會過度誇大效果量(就像本文的 337% 數字)。例如,他回顧了神經科學的多篇論文,發現檢定力只有 8 ~ 31% 這麼低的假設檢定,它們宣稱的效果量都被誇大了 25 ~ 50% 之多。

低檢定力的 A/B Test 有更高的 偽陽性率(False Positive Risk)、更可能誤判出相反結果、還會誇大效果,這些壞處都會狠狠傷害決策流程,我們身為資料科學家應盡全力避免低檢定力的 A/B 測試。那麼,究竟該怎麼解決 A/B Test 檢定力不足的問題呢?其實只要做好這兩個簡單、卻有很多人做不好的關鍵步驟:

  1. 實驗開始前,先 算好樣本數
  2. 在決定好的樣本數搜集完成以前,不偷看實驗、不做任何檢定;樣本 100% 搜集完成才做檢定

GuessTheTest 案例的樣本數只有 82 人,如果時間能重來、此實驗一開始乖乖照著步驟計算樣本數,應該要是多少呢?這裡我們再次理性、合理地把相對期望效果(Minimum Detactable Effect)設定為 10%(絕不是 337%!),加上先設定好檢定力 80% 與顯著水準 0.05,四大元素就只缺樣本數了,以下將同時列出多種樣本數算法:

# 算法 1
p = 3/82
n = TTestIndPower().solve_power(
     effect_size=proportion_effectsize(p, p*(1+0.1)), 
     nobs1=None, 
     alpha=0.05, 
     power=0.8)
n
# 43298.78872670578

# 算法 2
p = 3/82
delta = p*0.1
sigma = np.sqrt(p * (1-p))
n = 16 * sigma**2 / delta ** 2
n
# 42133.33333333334

# 算法 3
p = 3/82
n = sm.stats.samplesize_proportions_2indep_onetail(
    diff = p*0.1,
    prop2 = p,
    power = 0.8,
    alpha=0.05
)
n
# 43320.71273825671

以上三種算法都可以算出(幾乎)相同的結果、講出一樣的結論:文章開頭的範例,想看到 10% 的指標成長的話,照理說樣本數要超過 4 萬人,但實際上該範例只搜集了 82 人的樣本,樣本數是這般地天差地別,要說只有 82 人的實驗「不夠力」,誰會不同意呢。

(如果你還不太熟上方的計算方法,推薦你參考這篇 結合 Python 與數學公式的 A/B 測試樣本數計算教學

我們的 Power Analysis 分析至此,本文的範例終於可以用一小段話來總結:

在目前控制組基礎轉換率為 3.7%(3/82)的前提下
如果期望 10% 轉換率成長、並讓檢定力達到 80%,我們至少需要 4 萬人的樣本數
而此案例只有 82 人,遠遠未達標準、顯然是檢定力不足的實驗
我們因此結論:不採納此 A/B 測試的結果,更傾向相信此結果是偽陽性錯誤

至於為什麼會有這種高達 337% 差異的偽陽性?是命運捉弄人吧 ʕ •ᴥ•ʔ

更嚴謹的解釋是型一錯誤,筆者好豪自己很喜歡這樣比喻:就算你知道某個箱子裡藍色與橘色球恰好各佔一半,你伸手抓一把、抓出 6 顆球全都是藍色(圖解在此),這種情況不是不可能,對吧?我也推薦用 A/A Test 的角度來理解實驗中的型一錯誤,有興趣的話請參考這篇 A/A Test 教學


結語:太複雜了嗎?乖乖「照規矩」做 A/B 測試就沒這些煩惱

我曾經看過某個專業資料科學團隊,明確寫出團隊不會為公司同仁提供什麼支援,除了成為寫 SQL 工具人之外,其中一項就是 — 不會協助分析「已經完成」的 A/B Test 結果,因為流程沒有經過嚴謹設計的 A/B 測試、只用結果數據來去脈絡化地分析,很難得到有意義的結論。

幫人家分析 A/B 測試,發現對方的實驗流程不嚴謹,卻又擔心指責對方要看他臭臉,這種燙手山芋,專家們當然不想接。

本篇討論的就是經典案例,沒有事先控制檢定力與樣本數的 A/B 測試,只看低 P 值的顯著結果去回推,就算算出高檢定力,根本不代表此實驗可信,實驗「實際上」的檢定力完全不夠。如同本文的 GuessTheTest 案例,檢定力不足經常來自樣本數過低,為了確保 80% 檢定力,我們本該搜集特定量級的樣本數,若沒有達成該樣本數、看到顯著就下結論,更可能得到偽陽性的結果。

要為這篇落落長的文章做個總結也非常簡單,請正在閱讀的你,盡力遵照正確流程進行 A/B 測試,先設定好檢定力、算出樣本數,再開始實驗。嚴謹的實驗流程,才能為你的決策品質把關。

(提醒:本篇筆記在 GuessTheTest 案例以 Python 計算的結果與原始論文略有不同,詳細參數與統計方法設定請洽 原文

本文參考資料:

最後,如果你對 A/B Testing 有興趣,相信你會喜歡我的 A/B Testing 系列文章,推薦你繼續閱讀:


如果這篇文章有幫助到你,歡迎追蹤好豪的 Facebook 粉絲專頁Threads 帳號,我會持續分享資料科學以及 A/B Test 的實務操作心得;也可以點選下方按鈕,分享給熱愛數據分析的朋友們。

推薦閱讀