快轉到主要內容

A/B 測試觸發機制實戰指南:Counterfactual Logging 讓機器學習演算法的實驗超高效率!

Ab-Testing Statistics
好豪
作者
好豪
Google 資料科學家,以部落格寫作記錄自己的知識焦慮,記下我看過的書、寫過的程式碼、以及數據分析工作的見聞。歡迎透過 此表單 點播新文章、或者給部落格任何回饋!
目錄

上一篇文章 中,我們探討了 A/B 測試的觸發機制(Trigger)如何解決稀釋效果問題,並且能將實驗所需樣本數減少近一半。理論聽起來很美好,下個問題自然會是:「我到底該怎麼做觸發?」

我在 Google 內部見識過多個團隊實作觸發機制,發現自己學的是專屬 Google 大廠的技術框架,對一般團隊來說參考價值有限。因此,這篇文章是我向各大科技公司(包括 Spotify 與 DoorDash 等)學習後的總結,將介紹三種層次的觸發方法:

  1. User-Level Triggering:最簡單的使用者層級觸發
  2. Exposure Logging:中等複雜度的曝光 Logging 觸發
  3. Counterfactual Logging:最精密的反事實 Logging 觸發(本文重點!

本篇學習筆記中,每種方法都將說明其適用情境、優缺點,以及實際案例。

如果你還不熟悉觸發機制的基礎概念,建議先閱讀 上一篇文章 了解觸發分析是什麼、以及為什麼需要做觸發。


方法一:User-Level Triggering
#

如同問卷調查會篩選受訪者一樣,我們只讓符合條件的使用者參加 A/B 測試

適用情境
#

User-Level Triggering 運用使用者層級資訊是最簡單的觸發方式,適合以下情況:

  • 實驗只影響特定使用者群體(如特定國家、付費用戶、特定裝置)
  • 可以在實驗開始之前就預先識別目標使用者
  • 團隊技術資源有限,無法投入資源開發複雜的 Logging 系統
User-Level Triggering(製圖:好豪)

實作方式
#

這種方法的核心概念是:在實驗平台設定階段就篩選使用者,只有符合條件的使用者才會被分配到實驗組或控制組。

實驗設定範例:

  • 目標使用者:country = 'France' AND user_type = 'premium'
  • 表示只有「法國」的「付費會員」會被納入實驗
  • 國家與付費類型這兩項資訊,在實驗開始之前就能輕易取得、並依據這些資訊分配 A/B 組
graph TB; subgraph "使用者層級觸發流程"; A[所有使用者] --> B{符合使用者
屬性條件?}; B -->|是| C[納入實驗]; B -->|否| D[排除]; C --> E[隨機分配
控制組 vs 實驗組]; end; style C fill:#90EE90; style D fill:#FFB6C1;

應用案例:Netflix 測試定價策略
#

(想像情境)假設 Netflix 只想在巴西測試新的定價策略,他們可以用使用者層級觸發,只針對該地區的使用者進行實驗。這種做法的設定非常直觀:

實驗條件:country = 'Brazil'
- 控制組(50%):看到現有定價 $8.99
- 實驗組(50%):看到新定價 $7.99

但這種方法存在明顯的缺點,雖然所有巴西使用者都被納入實驗,但並非所有人都會「感受到」定價方案的改變。例如:

  • 已經是年度訂閱的使用者,還在合約期間內就不會看到新價格
  • 使用家庭方案而不是主揪的成員帳號,不會接觸到付款頁面
  • 長期不活躍的使用者,根本不會登入看到任何變化

這些巴西使用者雖然符合 User-Level Triggering 條件、仍然「在實驗中」,但實際上沒有受到 A/B 測試內容影響,他們的數據只會稀釋真實的價格效果。

graph TB; subgraph "以國家層級做實驗觸發"; F[巴西使用者
✓ 納入實驗] --> G[繳年費訂閱的用戶
✗ 未看到新價格]; F --> H[家庭方案非主揪成員帳號
✗ 不接觸付款]; F --> I[不活躍使用者
✗ 根本未登入]; F --> J[真正受影響的使用者
✓ 看到新定價]; G --> K[User-Level Triggering:
仍會包含未受影響的使用者]; H --> K; I --> K; end; style J fill:#90EE90; style G fill:#FFB6C1; style H fill:#FFB6C1; style I fill:#FFB6C1; style K fill:#FFE6D1;

優缺點
#

User-Level Triggering 觸發的優點:

  • 實作最簡單:只需要在實驗平台設定篩選條件即可,不需要修改程式碼
  • 無需額外 Logging 系統:利用現有的使用者屬性資料即可
  • 適合 80% 的基礎實驗:大多 A/B 測試不會有誇張的稀釋效果問題,依照使用者層級做實驗已經足夠

缺點:

  • 無法處理動態行為:無法判斷使用者是否真的「看到」或「接觸到」實驗變化,仍包含大量雜訊會稀釋效果、影響結果判讀
    • 此問題可用方法二的 Exposure Logging 解決
  • 不適合演算法實驗:無法判斷新舊演算法是否產生不同結果
    • 此問題在方法三的 Counterfactual Logging 會詳述

方法二:Exposure Logging
#

等使用者真的看到被改動的頁面,才開始計算

適用情境
#

Exposure Logging(曝光 Logging)能做到比使用者層級更精準的觸發,適合:

  • 實驗改動特定頁面或功能
  • 需要確認使用者「真的看到」實驗變化
    • 例如 上一篇文章 的範例:需要確認網站使用者「有到達」結帳頁面
  • 大多數 UI/UX 實驗的標準做法
Exposure Logging(製圖:好豪)

實作方式
#

Exposure Logging 的核心是:當使用者觸發「特定行為」時才記錄為「曝光」,分析時只納入有曝光記錄的使用者

這種方法不是在實驗開始之前就篩選使用者,而是在實驗運行期間,根據使用者的實際行為來決定是否納入分析。

假如你正在 A/B 測試改善電商網站的結帳頁面設計,Exposure Logging 的做法是:

步驟 1:在關鍵頁面加入 logging 程式碼
當使用者進入結帳頁面時:
  記錄 exposure_event('checkout_page_viewed')

步驟 2:實驗正常進行
*所有* 使用者仍被分配到控制組或實驗組

步驟 3:篩選資料來分析結果
只分析有 exposure_event 記錄的使用者

這種做法在 client-side(前端)或 server-side(後端)實作都可行,取決於你的技術架構。

graph LR; subgraph "Exposure Logging 觸發流程"; A[使用者進入網站] --> B[被分配到實驗組/控制組]; B --> C{是否訪問
結帳頁面?}; C -->|是| D[記錄 exposure_event]; C -->|否| E[不記錄]; D --> F[納入分析]; E --> G[排除分析]; end; style D fill:#90EE90; style E fill:#FFB6C1; style F fill:#90EE90; style G fill:#FFB6C1;

應用案例:DoorDash 的欺詐偵測實驗
#

此技術部落格文章 中,DoorDash 實驗新的欺詐偵測演算法(Fraud Detection),如果演算法認為某個使用者很可疑,就在結帳前新增驗證流程、要求該使用者驗證信用卡來避免盜刷。此情境遇到了典型的稀釋效果問題:被演算法認定為可疑的使用者本來就不多。

沒有使用 Exposure Logging 時

  • 追蹤所有使用者:4,450 萬人
  • 實驗結果:統計上不顯著
  • 問題:絕大多數使用者根本沒被演算法認定成可疑、而不會經歷新的信用卡驗證流程,他們的數據只是雜訊

使用 Exposure Logging 後

  • 只追蹤真正需要額外驗證的使用者:29.2 萬人
  • 實驗結果:統計上顯著的欺詐率下降
  • 實驗靈敏度提升 160 倍(算法請見 原文 的 Example 1)

這個案例完美展現了 Exposure Logging 的威力:透過排除那些不可能受影響的使用者(有四千多萬人只是雜訊!),A/B 測試能夠更靈敏地偵測到真實的效果。

優缺點
#

Exposure Logging 觸發的優點:

  • 比使用者層級觸發(方法一)更精準:更精準地追蹤有可能接觸到變化的使用者
  • 適用於絕大多數 UX 實驗:按鈕顏色、頁面佈局、功能改動等
  • 技術複雜度適中:只需要在關鍵頁面或功能加入 Logging 程式碼
  • 效果顯著:如 DoorDash 案例所示,可以大幅提升實驗靈敏度

缺點:

  • 需要修改程式碼:必須在相關頁面或功能中加入新的 Logging 邏輯
  • 可能增加 Client-Server 溝通成本:Client-side logging 會增加 client-server 之間的 request & respond
  • 無法處理「結果相同」的情況:這點在方法一就有,到此依然還沒解決。對於演算法類實驗,做了 Exposure Logging 也無法判斷新舊版本是否產生不同結果
    • 此問題在方法三的 Counterfactual Logging 會詳述

方法三:Counterfactual Logging
#

確認新舊版本真的存在「不一樣」,才算數

適用情境
#

Counterfactual Logging(反事實 Logging)是觸發機制的「終極形態」,專門用於:

  • 機器學習演算法改動
  • 搜尋排序演算法測試
  • 推薦系統實驗
  • 任何新舊系統「大部分時候產生相同結果」的 A/B 測試

可以說任何跟機器學習演算法有關的 A/B 測試,都可以考慮運用 Counterfactual Logging 來大幅增加實驗靈敏度。

為什麼需要 Counterfactual Logging?如果你練習過用 Python 寫過機器學習演算法實作,一定有過這種經驗:最佳化機器學習模型的過程,有很多時候即使調整了 超參數,新模型的預測結果依然跟舊模型極度相似

想像你正在測試新的推薦演算法,新演算法可能對 90% 的使用者推薦相同的商品。對這 90% 使用者而言,實驗根本沒發生—控制組和實驗組看到的內容完全一樣

另種常見情況是,即使新演算法推薦內容不同,但新的推薦被放在排序的後方,所以使用者根本看不到,如下圖範例,即使 YouTube 的演算法 A/B 測試給出不同推薦內容,有可能使用者沒有把網頁往下滑,所以根本不會感受到演算法在 A 與 B 版本可能有什麼差別!

Counterfactual Logging(製圖:好豪)

這時 Counterfactual Logging 的方法就很有幫助了:只有當新舊演算法產生不同結果時,使用者才真正「被觸發」納入分析。就剛剛的推薦演算法範例而言,就是只觸發 10% 的使用者,因為新舊演算法對他們推薦不同的商品。

這比方法二又更前進一步:

  • Exposure Logging 只能判斷使用者「有沒有可能」看到這個功能
  • 但 Counterfactual Logging 精細地判斷:即使進入有改動的頁面,使用者「是否確實體驗到」新舊版本的不同

實作方式:雙軌並行
#

Counterfactual Logging 的實作需要系統「雙軌並行」:

對於每個給伺服器的請求:

  1. 執行使用者實際被分配的版本(顯示給使用者)
  2. 同時在背景執行另一個版本(不顯示、使用者看不到這個背景執行)
  3. 比較兩個版本的結果
  4. 如果結果不同 → 標記為「觸發」、納入 A/B 測試結果分析
    • 這就是反事實的意思—背景執行的版本與使用者實際看到的現實不同
  5. 如果結果相同 → 不納入分析

在 Google 的部分團隊,這種做法被稱為 Shadow Mode(影子模式),因為有一個版本像「影子」一樣在背景執行,但使用者看不到。

graph TB; subgraph "Counterfactual Logging:
Shadow Mode 雙軌並行"; A[使用者請求推薦] --> B{使用者分組}; B --> M[控制組] --> |實際| C[執行舊演算法
顯示結果]; C --> G{比較結果
是否不同?}; M --> |反事實| E[背景執行
新演算法]; B --> N[實驗組] --> |實際| D[執行新演算法
顯示結果]; D --> H{比較結果
是否不同?}; E --> G; F[背景執行
舊演算法] --> H{比較結果
是否不同?}; N --> |反事實| F; G -->|是| I[觸發 ✓
納入分析]; G -->|否| J[不觸發 ✗
排除分析]; H -->|是| K[觸發 ✓
納入分析]; H -->|否| L[不觸發 ✗
排除分析]; end; style I fill:#90EE90; style K fill:#90EE90; style J fill:#FFB6C1; style L fill:#FFB6C1;

範例解說:推薦系統實驗
#

假設你正在測試新的商品推薦演算法:

使用者 A(控制組)

  • 舊演算法推薦:[商品 1, 商品 2, 商品 3]
  • 新演算法(背景執行)會推薦:[商品1, 商品4, 商品5]
  • 結果不同 → 觸發 ✅
  • 使用者 A 在控制組,所以實際會看到舊演算法推薦的 [商品 1, 商品 2, 商品 3]

使用者 B(控制組)

  • 舊演算法推薦:[商品 6, 商品 7, 商品 8]
  • 新演算法(背景執行)也推薦:[商品 6, 商品 7, 商品 8]
  • 結果相同 → 不觸發 ❌
  • 使用者 B 的數據不納入分析,因為新舊演算法對他來說沒差別

使用者 C(實驗組)

  • 舊演算法(背景執行)推薦:[商品 9, 商品 10, 商品 11]
  • 新演算法推薦:[商品 9, 商品 10, 商品 42]
  • 結果不同 → 觸發 ✅
  • 使用者 C 在實驗組,所以實際會看到新演算法推薦的 [商品 9, 商品 10, 商品 42]

資料科學家的實驗結果分析: 只比較使用者 A 和使用者 C 的行為(兩者都被觸發),忽略使用者 B(未被觸發)。

應用案例:Spotify 的音樂推薦系統
#

Spotify 在其 技術部落格 分享,他們改進音樂推薦演算法時也面臨典型的低觸發率問題。新演算法可能只對少數使用者產生不同的推薦結果。

透過 Counterfactual Logging 的反事實記錄,Spotify 能夠:

  • 識別出新舊演算法真正產生不同推薦的使用者(觸發率約 5~15%)
  • 專注分析這些使用者的行為差異
  • 在相同時間內偵測到更細緻的效果改進

根據業界研究,對於觸發率為 5% 的實驗,Counterfactual Logging 可以將所需實驗時間減少 20 倍

優缺點
#

Counterfactual Logging 進行觸發的優點:

  • 最精準的觸發方式:只包含真正體驗到差異的使用者
  • 對低觸發率實驗效果最顯著:觸發率 < 10% 時,效益最明顯
  • 業界標準做法:Spotify、Booking.com、Netflix 等公司的演算法實驗都採用此方法

缺點:

  • 運算成本高
    • 每個請求需要雙軌並行兩套演算法(實際版本 + 反事實版本)
    • 如果新演算法計算複雜度高,系統負載會顯著增加
    • 需要評估是否值得為了更精確的實驗結果付出這個成本
  • 技術複雜度高
    • 讓演算法雙軌並行的做法顯然存在技術門檻,實驗平台要有支援才能做到
    • 需要完善的 Logging 系統記錄反事實結果
    • 最重要的是,要確保反事實執行的運算負擔不會大到傷害伺服器效能、不能影響使用者體驗
  • 跨服務協調:在微服務架構中,可能需要多個服務協調,Upstream 服務的決策需要傳遞給 Downstream 服務,要有統一的實驗協調機制才能做到

Counterfactual Logging 很精準很厲害,但就挺麻煩的 ˊ_>ˋ

對於這些缺點,《Trustworthy Online Controlled Experiments》書中提到業界常見的效能最佳化策略包括:

  • 非同步處理:將反事實計算移到非關鍵路徑,不影響使用者回應時間
  • 資料取樣策略:只對部分流量進行反事實記錄,而非 100% 流量
  • A/A’/B 實驗:用 A/A’/B 實驗來評估「效能差異」本身的影響
    • A 組不會有反事實運算,而 A’ 組強制加入反事實運算
    • A 組與 A’ 組的使用者所見結果保證一模一樣
    • 因此 A 與 A’ 組比較,會反映出效能影響

實作與最佳化都很複雜,所以產品團隊得從一開始就好好考慮何時值得投入 Counterfactual Logging

  • 稀釋效果大:觸發率 < 10%
  • 實驗對業務影響重大(如核心的推薦/搜尋演算法)
  • 團隊有足夠工程資源建置基礎設施

該選擇哪種觸發方法?
#

以下是方法選擇指南,也複習一下本篇學習筆記的所有內容:

比較維度User-LevelExposure LoggingCounterfactual Logging
實作難度⭐ 簡單⭐⭐ 中等⭐⭐⭐⭐⭐⭐ 很複雜!
精準度超高!
適用觸發率任意>10%<10% 最佳
效能成本高(雙倍運算量)
需要修改程式碼是(增加 Logging)是(Shadow Mode)
典型應用地區/使用者分類實驗UI/UX 改動演算法/ML 實驗

觸發方法決策流程
#

你的實驗類型是什麼?
│
├─ 使用者分類實驗(如特定國家/裝置)
│  → 使用 User-Level Triggering
│
├─ UI/UX 改動(頁面設計/按鈕/流程)
│  │
│  ├─ 預期觸發率 > 20%
│  │  → 可考慮 User-Level Triggering(更簡單)
│  │
│  └─ 預期觸發率 < 20%
│     → 建議 Exposure Logging(更精準)
│
└─ 演算法/機器學習實驗
   │
   ├─ 預期觸發率 > 10%
   │  → Exposure Logging 即可
   │
   └─ 預期觸發率 < 10%
      └─ 有充足工程資源?
         ├─ 是 → Counterfactual Logging(最佳選擇)
         └─ 否 → Exposure Logging(折衷方案)

實務建議
#

綜合我在 Google 所學以及上述 Spotify、DoorDash 等業界經驗,以下是專家們給 A/B 測試觸發機制的實務建議:

循序漸進地實作觸發
#

  • 第一階段:依照 User-Level 資訊觸發(例如選擇特定國家做實驗)是最基本的做法
  • 第二階段:從 Exposure Logging 開始增加觸發精準度
  • 第三階段:若機器學習演算法只影響到 < 10% 的使用者,則考慮 Counterfactual Logging、需要投資建置完整的「雙軌並行運算」基礎設施

常見陷阱 ⚠️
#

  • 過早投入複雜的 Counterfactual Logging,卻缺乏基礎設施支援
  • 忽略效能監控,導致反事實 Logging 拖垮系統效能
  • 觸發條件設計錯誤,導致樣本比例不匹配 (SRM)
  • 未評估觸發率(效果稀釋程度)就盲目實作,投入產出比不佳

效益評估指標
#

  • 觸發率實際受實驗影響使用者 / 總實驗使用者,評估效果稀釋程度
  • 樣本數減少比例:使用觸發後所需樣本數 vs 不使用時
  • 實驗靈敏度提升:最小可偵測效果(MDE)的改善幅度
  • 投入產出比:工程成本 vs 實驗效率提升

結語
#

大家都想做更快更精準的 A/B 測試,在跳入一些超酷炫方法(CUPED、Bayesian 等等)之前,觸發 Trigger 也是個降低樣本數並提升實驗靈敏度的好選擇。

觸發機制不是非黑即白的選擇,而是存在不同複雜度的做法,可以根據實驗情境、觸發率、團隊資源來決定最適合的方案:

  • User-Level Triggering:簡單實用,適合明確的使用者分群實驗
  • Exposure Logging:中等精準度,適合大多數 UI/UX 實驗,是改善觸發精確度的起點
  • Counterfactual Logging:最精準但最複雜,是機器學習演算法實驗的終極武器

最重要的不是使用最酷、最複雜的技術,而是選擇最適合你當下需求的方法。大多數團隊會從簡單的 Exposure Logging 開始,隨著經驗累積和需求增長,再逐步升級到更複雜的方案。

參考資料:


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