總和的 A/B 測試比率
語境
考慮一家在線銷售商品的公司的以下場景。一個用戶可以購買多個項目(即一籃子項目),其中一些特別重要並且被專門跟踪(我們稱它們為明星項目)。
我們希望測試算法的變化(例如推薦、風險評估、添加目標等等……),這可能會影響明星商品的銷售數量和總銷售額。
- 這是一個標準的 A/B 測試設置 -隨機化單元位於用戶級別。
- A/B測試的目的是比較算法變化的影響:對照組有原始算法,變體有新算法
- 一個關鍵的興趣指標被定義為明星商品銷售額與總銷售額的比率。這是每個 A 或 B 組範圍內所有用戶的所有事務的總和。
- 這意味著分析單元處於事務級別,與隨機化單元不同
- 在整個測試期間(例如 2 週)計算指標
所用指標的詳細信息
給定組 A 和一組用戶 UA=u1,u2,…,uNA ,每個用戶都參與了一個數字 tun 的交易。套裝 TA 在測試期間,A 組中所有用戶的所有交易是 TA=tu11,tu12,…tunm .
組 A 感興趣的度量是針對組 A 範圍內的所有事務定義的。總和是在事務級別,而不是用戶級別。
$$ \text{Metric}A = \frac{\sum{t_{i} \in T_A} \text{sales star items }}{\sum_{t_{i} \in T_A} \text{sales }$ }$
當然,我們可以修改定義來計算用戶級別的平均值,這將簡化一切,但這不是正在使用的指標。
問題
什麼樣的統計檢驗可以用於這樣的度量?另一個考慮因素是,儘管我們可以安全地假設用戶是 iid,但假設單個購買籃對於同一用戶來說是 iid 很可能是錯誤的。
以下是我遇到的一些想法,過去是否有任何 A/B 測試從業者遇到過類似的指標?
- 比例 z 檢驗
- 自舉和折刀
- 增量法
- 更改指標(最後的手段)
https://en.wikipedia.org/wiki/Ratio_estimator
編輯 - 一些說明
這個問題背後的原因是我經常看到在這種情況下使用比例的 z 檢驗。用於 A/B 測試的流行工具通常默認使用比例測試,業務用戶很少檢查測試有效所需的基本假設。@dnqxt 下面的答案就是一個很好的例子:“只需使用 z 比例檢驗!” - 但我希望看到一個嚴格的統計理由來說明為什麼(或為什麼不)這個測試可以在這種情況下使用。
我個人認為使用比例 z 檢驗在這裡不起作用,因為購買事件的銷售不是伯努利試驗。我認為我們不能說以分母出售的每一美元都可以被視為伯努利試驗,導致分子出售 0 或 1 個星項目美元。此外,由於隨機化單元處於用戶級別,同一用戶的購買事件不是獨立的(但我認為這是次要問題)。我在這裡可能是錯的,所以請隨時證明這一點!
我們還可以更改度量,使其成為伯努利/二項式,通過使用計數收斂到正常,但這將是最後的解決方案
\frac{# \text{sales with star items} }{# \text{sales}}
- 比例 z 檢驗
當您有二元結果時,這適用於不同的情況。比例的 z 檢驗比較了這些二元結果的比例。
(下面的一些論點是您將能夠進行 t 檢驗,對於大數而言,這與 z 檢驗大致相同。對於比例,您可以進行 z 檢驗,因為二項式分佈有一個參數來確定方差和均值,與正態分佈不同)
- 自舉
這將是可能的,但並不是真正必要的,因為 Delta 方法可以更直接地提供您觀察到的統計數據的錯誤。
- 增量法
您對兩個可能相關的變量的比率感興趣:1. 總銷售額和 2. 明星商品的銷售額。
這些變量可能是漸近正態分佈的,因為它們是來自許多個人的銷售額的總和(測試過程可以被認為是一個過程,例如從個人用戶的銷售額分佈中挑選個人用戶的銷售額樣本)。因此,您可以使用 Delta 方法。
此處描述了使用 Delta 方法估計比率的方法。Delta 方法的這種應用的結果實際上與Hinkley 的結果的近似值一致,這是兩個相關正態分佈變量的比率的精確表達式(Hinkley DV,1969,關於兩個相關正態隨機變量的比率,Biometrica vol. 56第 3 號)。
(旁注:正如西安在評論中所指出的,George Marsaglia 1965 年在JASA 第 60 卷第 309 期中給出了更早的準確表達描述。2006 年在Jstatsoft 第 16 卷第 4 期中給出了簡單的現代描述)
為了 Z=XY 和[X\Y]∼N([μx μy],[σ2xρσxσy ρσxσyσ2y])
確切的結果是: f(z)=b(z)d(z)a(z)31√2πσXσY[Φ(b(z)√1−ρ2a(z))−Φ(−b(z)√1−ρ2a(z))]+√1−ρ2πσXσYa(z)2exp(−c2(1−ρ2))和a(z)=(z2σ2X−2ρzσXσY+1σ2Y)12 b(z)=μXzσ2X−ρ(μX+μYz)σXσY+μYσ2Y c=μ2Xσ2Y−2ρμXμY+σXσY+μ2Yσ2Y d(z)=exp(b(z)2−ca(z)22(1−ρ2)a(z)2)基於漸近行為的近似值是:(對於 μY/σY→∞ ):F(z)→Φ(z−μX/μYσXσYa(z)/μY)當您插入近似值時,您最終會得到 Delta 方法的結果 a(z)=a(μX/μY) a(z)σXσY/μY≈a(μX/μY)σXσY/μY=(μ2Xσ2Yμ4Y−2μXρσXσYμ3Y+σ2Xμ2Y)12的值 μX,μY,σX,σY,ρ 可以從您的觀察中估計,這允許您估計單個用戶的分佈的方差和均值,並且與此相關的是多個用戶總和的樣本分佈的方差和均值。
- 更改指標
我相信至少對單個用戶的銷售額(而不是比率)分佈進行初步繪圖是很有趣的。最終您可能會遇到 A 組和 B 組中的用戶之間存在差異的情況*,*但是當您考慮比率的單個變量時,它恰好並不顯著(這有點類似於 MANOVA更強大比單一的方差分析測試)。
雖然了解組間差異,但您感興趣的指標沒有顯著差異,可能對您做出決策沒有太大幫助,但它確實有助於您理解基礎理論,並可能在下次設計更好的更改/實驗。
插圖
下面是一個簡單的說明:
讓來自用戶的銷售的假設分佈分佈為分數 a,b,c,d 這表明有多少用戶屬於特定情況(實際上這種分佈會更複雜):
star item sales 0$ 40$ other item sales 0$ a b 10$ c d
然後是具有 10000 個用戶的組的總數的樣本分佈,使用一種算法a=0.190,b=0.001,c=0.800,d=0.009
和其他算法a=0.170,b=0.001,c=0.820,d=0.009看起來像:其中顯示 10000 次運行吸引新用戶併計算銷售額和比率。直方圖用於比率的分佈。這些線是使用來自 Hinkley 的函數進行的計算。
- 您可以看到兩個總銷售額的分佈近似為多元正態分佈。比率的等值線表明,您可以很好地估計比率作為線性和(如前面提到的/鏈接的線性化 Delta 方法),並且高斯分佈的近似值應該可以很好地工作(然後您可以使用 t-測試大數字就像 z 測試一樣)。
- 您還可以看到,與僅使用直方圖相比,這樣的散點圖可能會為您提供更多信息和洞察力。
用於計算圖形的 R 代碼:
set.seed(1) # # # function to sampling hypothetic n users # which will buy star items and/or regular items # # star item sales # 0$ 40$ # # regular item sales 0$ a b # 10$ c d # # sample_users <- function(n,a,b,c,d) { # sampling q <- sample(1:4, n, replace=TRUE, prob=c(a,b,c,d)) # total dolar value of items dri = (sum(q==3)+sum(q==4))*10 dsi = (sum(q==2)+sum(q==4))*40 # output list(dri=dri,dsi=dsi,dti=dri+dsi, q=q) } # # function for drawing those blocks for the tilted histogram # block <- function(phi=0.045+0.001/2, r=100, col=1) { if (col == 1) { bgs <- rgb(0,0,1,1/4) cols <- rgb(0,0,1,1/4) } else { bgs <- rgb(1,0,0,1/4) cols <- rgb(1,0,0,1/4) } angle <- c(atan(phi+0.001/2),atan(phi+0.001/2),atan(phi-0.001/2),atan(phi-0.001/2)) rr <- c(90000,90000+r,90000+r,90000) x <- cos(angle)*rr y <- sin(angle)*rr polygon(x,y,col=cols,bg=bgs) } block <- Vectorize(block) # # function to compute Hinkley's density formula # fw <- function(w,mu1,mu2,sig1,sig2,rho) { #several parameters aw <- sqrt(w^2/sig1^2 - 2*rho*w/(sig1*sig2) + 1/sig2^2) bw <- w*mu1/sig1^2 - rho*(mu1+mu2*w)/(sig1*sig2)+ mu2/sig2^2 c <- mu1^2/sig1^2 - 2 * rho * mu1 * mu2 / (sig1*sig2) + mu2^2/sig2^2 dw <- exp((bw^2 - c*aw^2)/(2*(1-rho^2)*aw^2)) # output from Hinkley's density formula out <- (bw*dw / ( sqrt(2*pi) * sig1 * sig2 * aw^3)) * (pnorm(bw/aw/sqrt(1-rho^2),0,1) - pnorm(-bw/aw/sqrt(1-rho^2),0,1)) + sqrt(1-rho^2)/(pi*sig1*sig2*aw^2) * exp(-c/(2*(1-rho^2))) out } fw <- Vectorize(fw) # # function to compute # theoretic distribution for sample with parameters (a,b,c,d) # lazy way to compute the mean and variance of the theoretic distribution fwusers <- function(na,nb,nc,nd,n=10000) { users <- c(rep(1,na),rep(2,nb),rep(3,nc),rep(4,nd)) dsi <- c(0,40,0,40)[users] dri <- c(0,0,10,10)[users] dti <- dsi+dri sig1 <- sqrt(var(dsi))*sqrt(n) sig2 <- sqrt(var(dti))*sqrt(n) cor <- cor(dti,dsi) mu1 <- mean(dsi)*n mu2 <- mean(dti)*n w <- seq(0,1,0.001) f <- fw(w,mu1,mu2,sig1,sig2,cor) list(w=w,f=f,sig1 = sig1, sig2=sig2, cor = cor, mu1= mu1, mu2 = mu2) } # sample many ntr time to display sample distribution of experiment outcome ntr <- 10^4 # sample A dsi1 <- rep(0,ntr) dti1 <- rep(0,ntr) for (i in 1:ntr) { users <- sample_users(10000,0.19,0.001,0.8,0.009) dsi1[i] <- users$dsi dti1[i] <- users$dti } # sample B dsi2 <- rep(0,ntr) dti2 <- rep(0,ntr) for (i in 1:ntr) { users <- sample_users(10000,0.19-0.02,0.001,0.8+0.02,0.009) dsi2[i] <- users$dsi dti2[i] <- users$dti } # hiostograms for ratio ratio1 <- dsi1/dti1 ratio2 <- dsi2/dti2 h1<-hist(ratio1, breaks = seq(0, round(max(ratio2+0.04),2), 0.001)) h2<-hist(ratio2, breaks = seq(0, round(max(ratio2+0.04),2), 0.001)) # plotting plot(0, 0, xlab = "sum of total sales", ylab = "sum of star item sales", xlim = c(82000,92000), ylim = c(2500,6000), pch=21, col = rgb(0,0,1,1/10), bg = rgb(0,0,1,1/10)) title("sample distribution for sum of 10 000 users") # isolines brks <- seq(0, round(max(ratio2+0.02),2), 0.001) for (ls in 1:length(brks)) { col=rgb(0,0,0,0.25+0.25*(ls%%5==1)) lines(c(0,10000000),c(0,10000000)*brks[ls],lty=2,col=col) } # scatter points points(dti1, dsi1, pch=21, col = rgb(0,0,1,1/10), bg = rgb(0,0,1,1/10)) points(dti2, dsi2, pch=21, col = rgb(1,0,0,1/10), bg = rgb(1,0,0,1/10)) # diagonal axis phi <- atan(h1$breaks) r <- 90000 lines(cos(phi)*r,sin(phi)*r,col=1) # histograms phi <- h1$mids r <- h1$density*10 block(phi,r,col=1) phi <- h2$mids r <- h2$density*10 block(phi,r,col=2) # labels for histogram axis phi <- atan(h1$breaks)[1+10*c(1:7)] r <- 90000 text(cos(phi)*r-130,sin(phi)*r,h1$breaks[1+10*c(1:7)],srt=-87.5,cex=0.9) text(cos(atan(0.045))*r-400,sin(atan(0.045))*r,"ratio of sum of star items and sum of total items", srt=-87.5,cex=0.9) # plotting functions for Hinkley densities using variance and means estimated from theoretic samples distribution wf1 <- fwusers(190,1,800,9,10000) wf2 <- fwusers(170,1,820,9,10000) rf1 <- 90000+10*wf1$f phi1 <- atan(wf1$w) lines(cos(phi1)*rf1,sin(phi1)*rf1,col=4) rf2 <- 90000+10*wf2$f phi2 <- atan(wf2$w) lines(cos(phi2)*rf2,sin(phi2)*rf2,col=2)