No voy a robar el tiempo de nadie explicando qué es una prueba A/B. Diré solo que las voy a estudiar desde una perspectiva bayesiana y que voy a analizar críticamente la selección de las prioris.

Por centrar ideas, supongo que la tasa de éxito a priori está alrededor del 5% y que mis prioris van a ser, en principio, betas:

mu <- .05
sd <- .02

# cálculo de los parámetros de la beta correspondiente
beta_params <- function(mu, sd) {
  var <- sd^2
  tmp <- mu * (1 - mu) / var - 1
  a <- mu * tmp
  b <- (1 - mu) * tmp
  c(a = a, b = b)
}

parms <- beta_params(mu, sd)

print(parms)
#       a        b
#  5.8875 111.8625

Una elección estándar de las prioris sería considerar $A, B \sim \text{Beta}(a, b)$ independientes. Entonces cabe preguntarse si la distribución a priori es compatible o no con lo que se esperaría al observar datos y la respuesta es negativa.

En efecto, si se hace

n <- 1000

sample_prior_A <- rbeta(n, parms["a"], parms["b"])
sample_prior_B <- rbeta(n, parms["a"], parms["b"])

lift_distribution <- sample_prior_B / sample_prior_A - 1

hist(lift_distribution, main = "Prior distribution of the lift", xlab = "lift", freq = F, breaks = 50)

se obtiene la gráfica

Lift under independence of groups

que demuestra cómo la anterior elección da por plausibles lifts ($p_B / p_A -1$) poco realistas, demasiado alejados del cero.

(Nota: la elección de prioris sobre A y B induce una «priori implícita» para el lift, L. Volveré a usar el término «priori implícita» más abajo.)

Juan Orduz estudia en Bayesian Power Analysis for A/B Testing una formulación alternativa (planteada/sugerida por otros: consúltense los artículos que enlaza) en los siguientes términos:

$$A \sim \text{Beta}(a, b)$$ $$L \sim N(0, \sigma)$$

donde $L$ es el lift y $\sigma$ es un valor pequeño que fuerza al lift a priori a mantenerse en el rango del que espera una persona razonable:

mu_lift <- 0
sd_lift <- .1

lift_prior_distribution <- rnorm(n, mu_lift, sd_lift)

Y comienzan a ocurrir cosas.

La primera de ellas es que B está determinado por las distribuciones de A y L,

sample_prior_B_induced <- sample_prior_A * (1 - lift_prior_distribution)

y que B está correlado con A:

rho <- cor(sample_prior_A, sample_prior_B_induced)
# 0.969132

plot(sample_prior_A, sample_prior_B_induced)

A is correlated with B

Pero lo más significativo es que entonces B ya no es una $\text{Beta}(a, b)$. En efecto, aunque su media sigue siendo la misma que en el caso anterior, su varianza está ligeramente inflada. De hecho, es

$$\sigma^2_B = \sigma^2_A + (\sigma^2_A + \mu^2) \sigma^2_L$$

que, aunque en este caso es apenas ligeramente superior a la original, podría levantar suspicacias en gente con una tolerancia metodológica inferior a la mía.

Pero se me ocurre una formulación alternativa (usando cópulas, obviamente):

library(copula)

gc <- normalCopula(param = rho, dim = 2)

mv <- mvdc(
  copula    = gc,
  margins   = c("beta", "beta"),
  paramMargins = list(
    list(shape1 = parms["a"], shape2 = parms["b"]),
    list(shape1 = parms["a"], shape2 = parms["b"])
  )
)

samp <- rMvdc(n, mv)
colnames(samp) <- c("A", "B")

cor(samp, method = "pearson")
#          A         B
#A 1.0000000 0.9686657
#B 0.9686657 1.0000000

mean(samp[,"A"])
#[1] 0.05048211
mean(samp[,"B"])
#[1] 0.05047582

sd(samp[,"A"])
#[1] 0.02031405
sd(samp[,"B"])
#[1] 0.01997436

plot(samp)

A is correlated with B

Y con respecto al lift, se tiene

tmp <- samp[, "A"] / samp[, "B"] - 1
hist(tmp, main = "Prior distribution of the implicit lift", xlab = "lift", freq = F)

Induced lift prior distribution

La cuestión es ver cómo operativizar esta nueva priori en NumPyro, PyMC, Stan o similares. Supongo que se podrá. Igual le pregunto a Claude un día de estos.