📜  使用 R 编程进行 AB 测试

📅  最后修改于: 2022-05-13 01:54:31.068000             🧑  作者: Mango

使用 R 编程进行 AB 测试

拆分测试是 A/B 测试的另一个名称,它是一种常见或通用的方法。当人们想要测试新功能或产品时,它会在线使用。这里的主要议程是设计一个实验,提供可重复的结果并稳健地做出是否启动它的明智决定。通常,此测试包括通过代表变体 A 和 B 来比较两个网页,因为访问者数量相似,变体给出的转化率会更好。总体而言,这是一项实验,通过向实时访问者展示同一网页的两个或更多变体,将它们进行比较,并通过该实验确定哪个变体在给定目标方面表现更好。 A/B 测试不仅限于网页使用或限制,它还可以用于电子邮件、弹出窗口、注册表单、应用程序等。让我们 查看案例研究的例子。那么让我们用R语言来实现AB测试。

案例分析

假设我们有来自两个酒店预订网站的 A/B 测试结果,(注意:数据不是真实的)。首先,我们需要对数据进行测试分析;其次,我们需要从第一步获得的数据中得出结论,最后一步,我们向产品或管理团队提出建议或建议。

数据集摘要

从这里下载数据集。

  • 变体 A 来自控制组,它告诉网站上现有的功能或产品。
  • 变体 B 来自实验组,用于检查功能或产品的新版本,以查看用户是否喜欢它或是否增加了转化(预订)。
  • Converted 是基于给定的数据集,有两个类别是由逻辑值定义的。当客户完成预订时它将显示为真,当客户访问网站但未进行预订时它将显示为假。

检验假设

  • 零假设:版本 A 和 B 具有相同的转化或推动客户预订的概率。换句话说,A和B版本之间没有区别或没有影响
  • 备择假设:版本 A 和 B 具有不同的转换概率或推动客户预订,并且 A 和 B 版本之间存在差异。在推动客户预订方面,版本 B 优于版本 A。 PExp_B! = Pcont_A。

R中的分析

1.准备数据集并加载包含用于分析的相关包的tidyverse库。

R
# load the library
library(tidyverse)
  
# set up your own directory
setwd(“~egot_\\Projects\\ABTest”) 
  
# Using read.csv base import function  
ABTest <- read.csv("Website Results.csv", 
                   header = TRUE)
  
# save in your own directory
save(ABTest, file = "~rda\\ABTest.rda")


R
# Let's filter out conversions for variant_A  
conversion_subset_A <- ABTest %>% 
    filter(variant == "A" & converted == "TRUE")
  
# Total Number of Conversions for variant_A
conversions_A <- nrow(conversion_subset_A)
  
# Number of Visitors for variant_A
visitors_A <- nrow(ABTest %>% 
    filter(variant == "A"))
  
# Conversion_rate_A
conv_rate_A <- (conversions_A/visitors_A)  
print(conv_rate_A) # 0.02773925
  
# Let's take a subset of conversions for variant_B
conversion_subset_B <- ABTest %>% 
    filter(variant == "B" & converted == "TRUE")
  
# Number of Conversions for variant_B
conversions_B <- nrow(conversion_subset_B)
  
# Number of Visitors for variant_B
visitors_B <- nrow(ABTest %>% 
    filter(variant == "B"))
  
# Conversion_rate_B
conv_rate_B <- (conversions_B/visitors_B)  
print(conv_rate_B) # 0.05068493


R
uplift <- (conv_rate_B - conv_rate_A) / conv_rate_A * 100
uplift # 82.72%


R
# Pooled sample proportion for variants A & B
p_pool <- (conversions_A + conversions_B) / (visitors_A +
                                             visitors_B)
print(p_pool) # 0.03928325
  
# Let's compute Standard error for variants A & B (SE_pool)
SE_pool <- sqrt(p_pool * (1 - p_pool) * ((1 / visitors_A) + 
                                         (1 / visitors_B)))
print(SE_pool) # 0.01020014
  
# Let's compute the margin of error for the pool
MOE <- SE_pool * qnorm(0.975)
print(MOE) # 0.0199919
  
# Point Estimate or Difference in proportion
d_hat <- conv_rate_B - conv_rate_A


R
# Compute the Z-score so we
# can determine the p-value
z_score <- d_hat / SE_pool
print(z_score) # 2.249546


R
# Let's compute p_value 
# using the z_score value
p_value <- pnorm(q = -z_score, 
                 mean = 0, 
                 sd = 1) * 2
print(p_value) # 0.02447777


R
# Let's compute Confidence interval for the 
# pool using pre-calculated results
ci <- c(d_hat - MOE, d_hat + MOE) 
ci # 0.002953777 0.042937584
  
# Using same steps as already shown, 
# let's compute the confidence 
# interval for variants A separately
X_hat_A <- conversions_A / visitors_A
se_hat_A <- sqrt(X_hat_A * (1 - X_hat_A) / visitors_A) 
ci_A <- c(X_hat_A - qnorm(0.975) * se_hat_A, X_hat_A
          + qnorm(0.975) * se_hat_A) 
print(ci_A) # 0.01575201 0.03972649
  
# Using same steps as already shown, 
# let's compute the confidence 
# interval for variants B separately                                 
X_hat_B <- conversions_B / visitors_B
se_hat_B <- sqrt(X_hat_B * (1 - X_hat_B) / visitors_B) 
ci_B <- c(X_hat_B - qnorm(0.975) * se_hat_B, 
          X_hat_B + qnorm(0.975) * se_hat_B) 
print(ci_B) # 0.03477269 0.06659717


R
vis_result_pool <- data.frame(
  metric = c(
    'Estimated Difference',
    'Relative Uplift(%)',
    'pooled sample proportion',
    'Standard Error of Difference',
    'z_score',
    'p-value',
    'Margin of Error',
    'CI-lower',
    'CI-upper'),
  value = c(
    conv_rate_B - conv_rate_A,
    uplift,
    p_pool,
    SE_pool,
    z_score,
    p_value,
    MOE,
    ci_lower,
    ci_upper
  ))
vis_result_pool


2. 让我们过滤变体 A 和 B 的转化并计算它们相应的转化率

电阻

# Let's filter out conversions for variant_A  
conversion_subset_A <- ABTest %>% 
    filter(variant == "A" & converted == "TRUE")
  
# Total Number of Conversions for variant_A
conversions_A <- nrow(conversion_subset_A)
  
# Number of Visitors for variant_A
visitors_A <- nrow(ABTest %>% 
    filter(variant == "A"))
  
# Conversion_rate_A
conv_rate_A <- (conversions_A/visitors_A)  
print(conv_rate_A) # 0.02773925
  
# Let's take a subset of conversions for variant_B
conversion_subset_B <- ABTest %>% 
    filter(variant == "B" & converted == "TRUE")
  
# Number of Conversions for variant_B
conversions_B <- nrow(conversion_subset_B)
  
# Number of Visitors for variant_B
visitors_B <- nrow(ABTest %>% 
    filter(variant == "B"))
  
# Conversion_rate_B
conv_rate_B <- (conversions_B/visitors_B)  
print(conv_rate_B) # 0.05068493

输出:

0.02773925
0.05068493

3.让我们使用转化率 A 和 B 计算相对提升。提升是增加的百分比

电阻

uplift <- (conv_rate_B - conv_rate_A) / conv_rate_A * 100
uplift # 82.72%

输出:

82.72%

B 比 A 好 83%。这足以决定获胜者。

4. 让我们计算变体 A 和 B 的合并概率、标准误差、误差幅度和比例差异(点估计)



电阻

# Pooled sample proportion for variants A & B
p_pool <- (conversions_A + conversions_B) / (visitors_A +
                                             visitors_B)
print(p_pool) # 0.03928325
  
# Let's compute Standard error for variants A & B (SE_pool)
SE_pool <- sqrt(p_pool * (1 - p_pool) * ((1 / visitors_A) + 
                                         (1 / visitors_B)))
print(SE_pool) # 0.01020014
  
# Let's compute the margin of error for the pool
MOE <- SE_pool * qnorm(0.975)
print(MOE) # 0.0199919
  
# Point Estimate or Difference in proportion
d_hat <- conv_rate_B - conv_rate_A

输出:

0.03928325
0.01020014
0.0199919

5. 让我们计算 z-score

电阻

# Compute the Z-score so we
# can determine the p-value
z_score <- d_hat / SE_pool
print(z_score) # 2.249546

输出:

2.249546

6. 使用这个 z-score,我们可以通过查找表或使用以下代码快速确定 p 值:

电阻

# Let's compute p_value 
# using the z_score value
p_value <- pnorm(q = -z_score, 
                 mean = 0, 
                 sd = 1) * 2
print(p_value) # 0.02447777

输出:

0.02447777

7. 让我们计算池的置信区间

电阻

# Let's compute Confidence interval for the 
# pool using pre-calculated results
ci <- c(d_hat - MOE, d_hat + MOE) 
ci # 0.002953777 0.042937584
  
# Using same steps as already shown, 
# let's compute the confidence 
# interval for variants A separately
X_hat_A <- conversions_A / visitors_A
se_hat_A <- sqrt(X_hat_A * (1 - X_hat_A) / visitors_A) 
ci_A <- c(X_hat_A - qnorm(0.975) * se_hat_A, X_hat_A
          + qnorm(0.975) * se_hat_A) 
print(ci_A) # 0.01575201 0.03972649
  
# Using same steps as already shown, 
# let's compute the confidence 
# interval for variants B separately                                 
X_hat_B <- conversions_B / visitors_B
se_hat_B <- sqrt(X_hat_B * (1 - X_hat_B) / visitors_B) 
ci_B <- c(X_hat_B - qnorm(0.975) * se_hat_B, 
          X_hat_B + qnorm(0.975) * se_hat_B) 
print(ci_B) # 0.03477269 0.06659717

输出:

0.002953777 0.042937584
0.01575201 0.03972649
0.03477269 0.06659717

8. 让我们在数据框(表)中可视化到目前为止计算的结果

电阻

vis_result_pool <- data.frame(
  metric = c(
    'Estimated Difference',
    'Relative Uplift(%)',
    'pooled sample proportion',
    'Standard Error of Difference',
    'z_score',
    'p-value',
    'Margin of Error',
    'CI-lower',
    'CI-upper'),
  value = c(
    conv_rate_B - conv_rate_A,
    uplift,
    p_pool,
    SE_pool,
    z_score,
    p_value,
    MOE,
    ci_lower,
    ci_upper
  ))
vis_result_pool

输出:

metric       value
1         Estimated Difference  0.02294568
2           Relative Uplift(%) 82.71917808
3     pooled sample proportion  0.03928325
4 Standard Error of Difference  0.01020014
5                      z_score  2.24954609
6                      p-value  0.02447777
7              Margin of Error  0.01999190
8                     CI-lower  0.00000000
9                     CI-upper  0.04589136

建议与结论

  • 变体 A 有 20 次转化和 721 次点击,而变体 B 有 37 次转化和 730 次点击。
  • 基于变体 A 转换率的 82.72% 的相对提升为 2.77%,B 为 5.07%。因此,变体 B 比 A 好 82.72%。
  • 对于该分析,计算的 P 值为 0.02448。因此,测试结果具有很强的统计意义。
  • 从上述结果可以看出具有很强的统计意义。您应该拒绝零假设并继续启动。
  • 因此,接受变体 B,您可以将其 100% 滚动给用户。

如果您想了解完整的分析和数据集详细信息,请单击此 Github 链接。

限制

它是转换优化的工具之一,它不是一个独立的解决方案,它不会解决我们所有的转换问题,也无法解决您处理杂乱数据时遇到的问题,您需要执行的不仅仅是一个A/B 测试以提高转化率。