????????通常在比較兩個不同的方案對數據的影響時,我們會各拿50%的數據去進行對照試驗,這樣觀測到的結果會最大程度地保留統計學上的特點。但實際上,并不是所有對比不同方案都要這樣做,一來,我們需要等到兩組實驗都完全結束后,才能知道結果如何,等待時間周期較長;二來,在很多場景中,差的方案會在落地測試時不可避免地對用戶造成不好的體驗。
????????后者對應的一般是在用戶的實時反饋和廣告的點擊率上,那么這種情況,我們會采用動態規劃的方式,隨著實驗的進行,不斷地減少差方案的數據,通過這種迭代的方式來降低額外的損失,從而實現快速地聚焦到優質方案。當然,這樣做會在一定程度上破壞數據的分布,統計顯著性會減弱。
以下是一個例子:????????
library(bayesAB)
# 生成模擬數據集:3個廣告版本(A/B/C)的點擊率
# 生成模擬數據集:每天隨機選一個廣告測試
set.seed(123)
n_days <- 25 # 測試5天
true_rates <- c(A = 0.1, B = 0.15, C = 0.2) # 真實點擊率generate_data <- function(day) {chosen_ad <- sample(c("A", "B", "C"), 1) # 每天隨機選一個廣告impressions <- sample(100:500, 1)clicks <- rbinom(1, size = impressions, prob = true_rates[chosen_ad])data.frame(day = day,ad_version = chosen_ad,impressions = impressions,clicks = clicks)
}ad_data <- do.call(rbind, lapply(1:n_days, generate_data))
head(ad_data)# 多臂老虎機算法(Epsilon-Greedy)
run_bandit <- function(data, epsilon = 0.1) {total_rewards <- c(A = 0, B = 0, C = 0)total_trials <- c(A = 0, B = 0, C = 0)choices <- character(n_days)for (day in 1:n_days) {day_data <- subset(data, day == day)if (nrow(day_data) == 0) nextif (runif(1) < epsilon) {chosen_ad <- sample(day_data$ad_version, 1) # 從當天實際廣告中隨機選} else {ctr <- ifelse(total_trials > 0, total_rewards / total_trials, 0)chosen_ad <- names(which.max(ctr))}# 只取第一個匹配項(避免多行問題)ad_data <- subset(day_data, ad_version == chosen_ad)[1, ]if (!is.na(ad_data$ad_version)) {total_rewards[chosen_ad] <- total_rewards[chosen_ad] + ad_data$clickstotal_trials[chosen_ad] <- total_trials[chosen_ad] + ad_data$impressionschoices[day] <- chosen_ad}}prop.table(table(choices[choices != ""]))
}result <- run_bandit(ad_data)
print(paste("最終選擇比例:", round(result * 100, 1), "%"))
輸出:
[1] "最終選擇比例: 24 %" "最終選擇比例: 76 %"
結果顯示,在25天的模擬中,多臂老虎機算法最終分配了24%的流量給某個廣告版本(可能是A或B),76%給另一個版本,符合原理的表現,同時24%的數據給另一個方案則保留了可能萬一真的忽略了潛在方案的可能。