首页 > 其他分享 >AB_test

AB_test

时间:2023-03-14 18:34:05浏览次数:30  
标签:control AB NC round experiment GC test click

import math
import numpy as np
import pandas as pd
# import statistics as stats
from scipy.stats import norm

A/B Test 步骤

  1. 确定测量指标、实验指标、不变指标
    1. 确定自己需要估计的量
    2. 确定改变的量 / 即所要施加的措施
    3. 确定不变的量
    4. 确定最小可检出量
  2. 测定当下变量的表现(即 Base / 或者叫对照组)
  3. 设计实验
    1. 实验最小样本量
    2. 实验时长
    3. 分流措施:可能会影响实验的结果
  4. 获取检验量的分布
  5. 基于分布和问题确定有关检验
  6. 计算显著性

1. 实验目标

本次实验旨在验证所采取措施对 Udacity 网课的留存率、登记率的影响是否足够显著。

2. 情况描述

2.1 当前情形描述

At the time of this experiment, Udacity courses currently have two options on the course overview page: "start free trial", and "access course materials".

  • If the student clicks "start free trial", they will be asked to enter their credit card information, and then they will be enrolled in a free trial for the paid version of the course. After 14 days, they will automatically be charged unless they cancel first.
  • If the student clicks "access course materials", they will be able to view the videos and take the quizzes for free, but they will not receive coaching support or a verified certificate, and they will not submit their final project for feedback.

2.2 所采取措施

In the experiment, Udacity tested a change where if the student clicked "start free trial", ?they were asked how much time they had available to devote to the course.

  • If the student indicated 5 or more hours per week, they would be taken through the checkout process as usual. If they indicated fewer than 5 hours per week, a message would appear indicating that Udacity courses usually require a greater time commitment for successful completion, and suggesting that the student might like to access the course materials for free.
  • At this point, the student would have the option to continue enrolling in the free trial, or access the course materials for free instead. This screenshot shows what the experiment looks like.
    对尝试免费使用的客户进行一个预筛选,在保证留存率的前提下,减少登记率

2.3 实验假设

The hypothesis was that this might set clearer expectations for students upfront, thus reducing the number of frustrated students who left the free trial because they didn't have enough time—without significantly reducing the number of students to continue past the free trial and eventually complete the course. If this hypothesis held true, Udacity could improve the overall student experience and improve coaches' capacity to support students who are likely to complete the course.

2.4 实验细节

The unit of diversion is a cookie, although if the student enrolls in the free trial, they are tracked by user-id from that point forward. The same user-id cannot enroll in the free trial twice.
For users that do not enroll, their user-id is not tracked in the experiment, even if they were signed in when they visited the course overview page.

3. 评测指标选取

3.1 变化指标与不变指标

  • 变化指标是我们通过措施企图影响的指标,用于验证实验效果
  • 不变指标是我们不希望在实验中看到变化的指标,用于保证实验检测的有效性

变化指标是我们企图在实验组和对照组中看到变化的指标;不变指标是我们不希望在实验组和对照组中看到区别的指标

3.2 最小变化量

我们在实验中需要观测到的最小变化量,只有大于最小变化量,对于实际商业中才有意义。
而最小变化量也有利于帮助我们确定其他实验指标

3.3 不变指标

Metric Name Metric Formula \(D_{min}\) Notian
Number of Cookies in Course Overview Page # unique daily cookies on page 3000 cookies \(C_k\)
Number of Clicks on Free Trial Button # unique daily cookies who clicked 240 clicks \(C_l\)
Free Trial button Click-Through-Probability \(\frac{C_l}{C_k}\) 0.01 \(CTP\)

3.4 评估指标---表现指示器

Metric Name Metric Formula \(D_{min}\) Notian
Gross Conversion \(\frac{erolled}{C_l}\) 0.01 \(Conversion_{Gross}\)
Retention \(\frac{paid}{enrolled}\) 0.01 \(Retention\)
Net Conversion \(\frac{paid}{C_l}\) 0.0075 \(Conversion_{Net}\)

4. 估计指标的基本值

在实验之前,我们得先了解现状!这是告诉我们实验是否真实发生了改变的前提。
因为我们的目的是改变现状,如果都不了解现状,谈何改变

4.1 收集需要评估的数据的现状

Udacity 已经给了

Base_info = pd.read_csv('Final Project Baseline Values - Sheet1.csv', header=None)
Base_info.columns=["name", "data"]
Base_info["name"] = ['cookie', 'click', 'Enrollments', 'CTP', 'GConversion', 'Retention', 'NConversion']
Baseline = {
    'cookie':40000, 
    'click':3200, 
    'Enrollments':660, 
    'CTP':0.080000, 
    'GConversion':0.206250, 
    'Retention':0.530000, 
    'NConversion':0.109313
}

4.2 评估标准差(SD)

这是通过现状来对需要评测的指标计算一个标准差。
这是为样本量计算结果的置信区间计算的。指标的变体越大,就越难获得显着的结果

4.2.1 缩放数据

项目中说使用 5000 来作为我们评估标准差的样本大小,我们希望基于这 5000 这个量来估计指标的标准差所以,我们需要将之前数据中的数据做一个缩放:

  • 绝对数据需要缩放
  • 相对比例不需要缩放
Baseline['cookie'] = Baseline['cookie'] * (5000/40000)
Baseline['click'] = Baseline['click'] * (5000/40000)
Baseline['Enrollments'] = Baseline['Enrollments'] * (5000/40000)
Baseline
{'cookie': 5000.0,
 'click': 400.0,
 'Enrollments': 82.5,
 'CTP': 0.08,
 'GConversion': 0.20625,
 'Retention': 0.53,
 'NConversion': 0.109313}

4.2.2 估算对应数据

我们使用采样的数据进行估算,得到对应概率的标准差: \(X_i\) 服从 0,1 分布,我们使用样本量为 n 概率为 p 的伯努利分布来获取 \(\hat{p}\)

\[E({p}) = E(\frac{1}{n} \sum_1^n X_i) = \frac{1}{n} \sum_1^n E(X_i)= p \\ Var({p}) = Var(\frac{1}{n} \sum_1^n X_i) = \frac{1}{n^2} \sum_1^n Var(X_i) = \frac{p(1-p)}{n} \]

所以:

\[SD = \sqrt{\frac{p(1-p)}{n}} \]

而我们使用 baseline 中的 \(\hat{p}\) 作为 p 的估计,则:

\[SD = \sqrt{\frac{\hat{p}(1-\hat{p})}{n}} \]

这个假设只在unit of diversionunit of analysis(度量公式的分母)一致时有效。也就是说,如果两者不一样,对于该统计量的分布是不同的。样本量越大,统计量的方差分布越小。那么在之后的计算中,我们就需要保证每次划分单元的计算都放缩到对应的数据量上来

  • unit of diversion(分流单元),被用来定义哪个用户或者触发那个事件会进行样本分流(实验组和对照组)
  • unit of analysis 分析单元(通常是指标的分母)
  • 指标变化性(Variability of metric):这里的变化性,我认为就是变化性越大,代表样本指标值之间的波动会比较大。如果分流单元比分析单元的范围更大,则指标的变化性要高得多。分析单元一般是指标的分母。例如,对于点击率(CTR)(定义为#Click/#PV),#PV成为分析单元。因此,如果我们使用user_id作为我们的分流单元,以pv作为我们的分析单元,CTR的变化性就会变高。因为一个user_id可以对应多个pv。
  • 用户一致性(User consistency):如果我们上线的策略对用户是可见的(例如UI类实验,改下button颜色啥的),原则是让用户始终有一致的体验。因此,选User_ID或Cookie作为分流单元是不错的选择。如果我们上线的策略对用户是不可见的,那么基于事件的分流,如页面浏览将更有意义。因为这样,每次用户重新加载页面时,他们可能会被分配给一个新的组,即如果用户最初是在实验组,现在他们可能会在控制组中结束实验。(PS:这一点没有理解,欢迎有经验的同学探讨,为什么不可见的策略可以用事件触发分流?)

Gross Conversion

# Let's get the p and n we need for Gross Conversion (GC)
# and compute the Stansard Deviation(sd) rounded to 4 decimal digits.
GC={}
GC['d_min'] = 0.01
GC['p'] = Baseline['GConversion']
#p is given in this case - or we could calculate it from enrollments/clicks
GC['n'] = Baseline['click']
# 在数据较小时,round 是一个很重要的函数,避免直接变为 0 
GC['sd'] = round(math.sqrt(GC['p']*(1-GC['p']) / GC['n']),4)
GC['sd']
0.0202

Retention

R={}
R['d_min'] = 0.01
R['p'] = Baseline['Retention']
#p is given in this case - or we could calculate it from enrollments/clicks
R['n'] = Baseline['Enrollments']
# 在数据较小时,round 是一个很重要的函数,避免直接变为 0 
R['sd'] = round(math.sqrt(R['p']*(1-R['p']) / R['n']),4)
R['sd']
0.0549

Net Conversion

NC={}
NC['d_min'] = 0.0075
NC['p'] = Baseline['NConversion']
NC['n'] = Baseline['click']
NC['sd'] = round(math.sqrt(NC['p']*(1-NC['p']) / NC['n']),4)
NC['sd']
0.0156

以上,对当下情况进行了一个总结。

  • 理清了实验目的
  • 确定了 Invariate MetrixEvaluation Metric
  • 基于现有数据,对 Metrix 的 baseline 进行了计算

之后就开展实验分析

5. 实验所需最小样本量

在显著性检验中,我们需要基于样本统计量的分布,最小检出要求(\(d_{min}\)),计算满足指定 显著等级(\(\alpha = 0.05\))检验效能(\(\beta=0.2\)) 的最小样本量,来保证结果的显著性及统计能力

\(1-\beta\) 通常被认为时 sensitivity:即有差异时,能被检出的概率(通常取 80%)

  • 结果的显著性:差异在统计学上是足够显著的
  • 统计能力:能够在有差异的情况下,检测出差异。即能够正确拒绝原假设。原因是我们不想在原假设错误(即两者有差异)的情况下,因为样本量不够,我们将差异归结为随机性,从而依旧接受了原假设。

    也就是说:哪怕有差异,我们因为 统计能力/检验效能 不足,导致我们差异未达到显著等级,将计算出的差异当成了随机性。
    也就是:哪怕我们有时候检出差异没有达到显著等级,也并不代表两者没有差异。只是我们将其归结为了随机性,从而错误的接受了原假设。

而增大样本量能减少样本统计量分布的方差,从而减少了在检出差异没有达到显著等级时接受原假设的概率

单组样本量计算公式:

\[\begin{gather} n = \frac{(Z_{1-\frac{\alpha}{2}}\times sd_1 + Z_{1-\beta}\times sd_2)^2}{d^2}, with \\ sd_1 = \sqrt{p(1-p) + p(1-p)} \\ sd_2 = \sqrt{p(1-p) + (p+d)(1-(p+d))} \end{gather} \]

服从正态分布的随机变量和对应的分布也是一个正态分布,具体参数取决于变量的数量、均值以及方差。

假设有 \(n\) 个服从正态分布 \(X_i\sim N(\mu_i,\sigma_i^2)\) 的随机变量 \(X_1, X_2, \cdots, X_n\) ,它们的和为 \(S=X_1+X_2+\cdots+X_n\)。则:

当方差相等时,即 \(\sigma_1^2=\sigma_2^2=\cdots=\sigma_n^2=\sigma^2\),和的分布是 \(S\sim N(\sum_{i=1}^n \mu_i,n\sigma^2)\)。

当方差不等时,或者说协方差矩阵非对角线上的元素不为零,此时需要使用多元正态分布的公式才能求解和的分布,具体而言,和的分布可以表示为 \(S\sim N(\boldsymbol{\mu},\boldsymbol{\Sigma})\),其中 \(\boldsymbol{\mu}\) 是每个随机变量的均值构成的向量,\(\boldsymbol{\Sigma}\) 是所有随机变量之间的协方差矩阵。若互相独立,则是各正态随机变量方差的和

当均值相等时,即 \(\mu_1=\mu_2=\cdots=\mu_n=\mu\),和的分布是 \(S\sim N(n\mu,n\sigma^2)\),其中 \(\sigma^2\) 是每个随机变量的方差。

当均值不等时,而且方差也不等,此时需要使用多元正态分布的公式,和的分布可以表示为 \(S\sim N(\boldsymbol{\mu},\boldsymbol{\Sigma})\),其中 \(\boldsymbol{\mu}\) 是每个随机变量的均值构成的向量,\(\boldsymbol{\Sigma}\) 是所有随机变量之间的协方差矩阵。

在未完成的有限推导下,对上式个人的理解为:

  • 在计算显著性时,假设是在原假设的条件下进行的,此时两个总体的方差相等,所以在此基础上计算显著性时推导出的 \(sd_1 = \sqrt{p(1-p) + p(1-p)}\)
  • 在计算检验效能时,假设是在备择假设的条件下进行的,此时两个总体的方差不相等,所以在此基础上计算检验效能时推导出的 \(sd_2 = \sqrt{p(1-p) + (p+d)(1-(p+d))}\)

先计算原假设的显著性,然后在此基础上计算检验效能。最后就能得到所需的样本量

def get_sample_num(alpha, beta, p, d):
    sd1 = math.sqrt(p*(1-p) + p*(1-p))
    sd2 = math.sqrt(p*(1-p) + (p+d)*(1-(p+d)))
    return math.pow(norm.ppf(1-alpha/2)*sd1 + norm.ppf(1-beta)*sd2, 2) / math.pow(d,2)

Gross Conversion 需要样本量计算

# 这里计算得到的是基于 click 的转化率,即 n 表示的是单组需要的 click 的数量
GC['SampleSize'] = round(get_sample_num(0.05, 0.2, GC['p'], GC['d_min']))
GC['SampleSize']
25835
# 但我们最终需要的是 pageview 的数量
# 而 click / pageview = 0.08
GC['SampleSize'] = round(GC['SampleSize'] / 0.08 , 2)
# 现在计算 A/B 两组共需要多少样本量
GC['SampleSize'] = round(GC["SampleSize"] * 2, 2)
GC['SampleSize']
645875.0

retention 需要样本量计算

R['SampleSize'] = round(get_sample_num(0.05, 0.2, R['p'], R['d_min']))
R['SampleSize'] = round(R['SampleSize'] / (Baseline['Enrollments'] / Baseline['cookie']) , 2)
R['SampleSize'] = round(R['SampleSize'] * 2 , 2)
R['SampleSize']
4737818.18

这太大了,在有限实验时长中不可忍受

Net Conversion 需要样本量计算

NC['SampleSize'] = round(get_sample_num(0.05, 0.2, NC['p'], NC['d_min']))
NC['SampleSize'] = round(NC['SampleSize'] / 0.08 , 2)
NC['SampleSize'] = round(NC['SampleSize'] * 2 , 2)
NC['SampleSize']
685325.0

NC['SampleSize'] > GC['SampleSize'], 故我们取 NC['SampleSize'] 可以同时满足两者

6. 分析收集到的数据,开始检验

6.1 加载数据

control = pd.read_csv('control_data.csv')
experiment = pd.read_csv('experiment_data.csv')
control.head()
Date Pageviews Clicks Enrollments Payments
0 Sat, Oct 11 7723 687 134.0 70.0
1 Sun, Oct 12 9102 779 147.0 70.0
2 Mon, Oct 13 10511 909 167.0 95.0
3 Tue, Oct 14 9871 836 156.0 105.0
4 Wed, Oct 15 10014 837 163.0 64.0

6.2 Sanity Test

主要用于检验控制变量的稳定性,从而保证此次实验分析结果的有效性

6.2.1 Sanity Test Of PageView

# 统计 A / B 组的 PageView 总量
control_pv = control['Pageviews'].sum()
experiment_pv = experiment['Pageviews'].sum()
total_pv = control_pv + experiment_pv
print('control_pv: {0}, experiment_pv:{1}'.format(control_pv, experiment_pv))
control_pv: 345543, experiment_pv:344660
# p_hat_pageview 表示实验时,pageView 被分到 control 组的概率
p_hat_pageview = round(control_pv / total_pv, 4)
p_hat_pageview
0.5006

可以看到两者的差距并不大,我们认为其是由于随机性引起的小差异(假设),我们需要对这个假设进行一个检验

我们将用户被分为哪个组视为一个 0-1 分布,并且将分到 control 组视为 1,并且假定 \(p = 0.5\)

同时,我们使用伯努利实验来估计 \(p\) ,方法为将样本(大小为 n , 且也是伯努利实验中重复的次数)中的 \(\frac{control_{num}}{total_{num}}\) 当作 \(p\) 的估计 \(\hat{p}\)

由此可得:

\[\begin{gather} E(\hat{p}) = p \\ Var(\hat{p}) = \frac{p\times (1-p)}{n} \end{gather} \]

我们由中心极限定理可推:

假设 \(X_1, \cdots, X_n\) iid, 且 \(E(X_i) = a\),\(Var(X_i)=\sigma^2\) ,则:

\[\lim_{n\to \infty} P(\frac{1}{\sqrt{n}\sigma}X_1 + \cdots + X_n - n\alpha) \le x = \Phi(x) \]

上下同除 n 可得:

\[\begin{gather} \lim_{n\to \infty} P(\frac{1}{\frac{\sigma}{\sqrt{n}}}\frac{(X_1 + \cdots + X_n)}{n} - \alpha) \le x = \Phi(x) \\ \lim_{n\to \infty} P(\frac{1}{\frac{\sigma}{\sqrt{n}}}(\hat{p} - \alpha)) \le x = \Phi(x) \end{gather} \]

将 \(X\) 服从 0-1 分布代入,得到 \(E(X_i) = p\),\(Var(X_i)=p(1-p)\), 则上式可变为:

\[\lim_{n\to \infty} P(\frac{(\hat{p} - p)}{\sqrt{\frac{p(1-p)}{n}}}) \le x = \Phi(x) \]

故,我们可用正态分布对 pageview 总数做检验:

  1. 我们假定每个 pageview 是等概率被分到两个组中,即 \(p = 0.5\)
  2. 我们设定置信水平为 \(\alpha=0.05\) 的检验
  3. 同时,我们直接计算 confidence interval 来获取接受域内 \(\hat{p}\) 的取值
def get_z_score(split_point):
    '''
    用于获得对应分为点的值, 即:
    返回标准正态分布从 负无穷 - result 积分值等于 split_point 对应的 result
    '''
    result = norm.ppf(split_point)
    return result
p_pv = 0.5
alpha_pv = 0.05
# SE 是统计量分布对应的标准差,具体可以见笔记
sd_pv = math.sqrt((0.5*(1-0.5))/total_pv)
print(f'pageview 置信度为 99.5 的置信区间为:[{p_pv - round(get_z_score(1-alpha_pv / 2)*sd_pv,4)},{p_pv + round(get_z_score(1-alpha_pv / 2)*sd_pv,4)}]')
pageview 置信度为 99.5 的置信区间为:[0.4988,0.5012]
  1. \(\hat{p}_{pageview} = 0.5006\)
  2. CI 为 \([0.4988, 0.5012]\)
  3. 故,pageview 通过 Sanity Test

6.2.2 Sanity Test of Click

同理,对 Click 的值进行稳定性检验,方法同 Sanity Test of Click

control_click = control['Clicks'].sum()
experiment_click = experiment['Clicks'].sum()
total_click = control_click + experiment_click
p_hat_click = round(control_click/total_click, 4)
print(f'control_click:   {control_click};\nexperiment_click:  {experiment_click};\ntotal_click:    {total_click}\n')
print(f'p_hat_click:   {p_hat_click}')
control_click:   28378;
experiment_click:  28325;
total_click:    56703

p_hat_click:   0.5005
p_click = 0.5
alpha_click = 0.05
# SE 是统计量分布对应的标准差,具体可以见笔记
sd_click = math.sqrt((0.5*(1-0.5))/total_click)
print(f'pageview 置信度为 99.5 的置信区间为:[{p_click - round(get_z_score(1-alpha_click / 2)*sd_click,4)},{0.5 + round(get_z_score(1-alpha_click / 2)*sd_click,4)}]')
pageview 置信度为 99.5 的置信区间为:[0.4959,0.5041]

6.2.3 Sanity Test of CTP

该部分是对 \(\frac{Click_{num}}{Pageview_{num}}\) 进行一个检验。
该部分检验的必要性在于我们必须要保证 A, B 两组在点击 Free Trial Button 的概率是稳定的,否则就会出现某一组有更高的概率尝试,这样就会导致会有更大的概率进行下一步的选择。
或者说有更大的可能进行尝试,这样就会引入不同的影响因子,导致实验结果不稳定

# 先计算出 CTP
control_ctp = control_click / control_pv
experiment_ctp = experiment_click / experiment_pv
total_ctp = total_click / total_pv
print(f'control_ctp:   {control_ctp};\nexperiment_ctp:  {experiment_ctp};\ntotal_ctp:     {total_ctp}')
control_ctp:   0.08212581357457682;
experiment_ctp:  0.08218244066616376;
total_ctp:     0.08215409089789526

我们使用 total_ctp 作为总体 p 的估计,并且 假设 Control 组 和 experiment 组的 ctp 相等,且均为 p_pool,则:

\[\begin{gather} ctp_{control} \sim N(p_{pool}, \frac{p_{pool}\times (1-p_{pool})}{PV_{control}}) \\ ctp_{experiment} \sim N(p_{pool}, \frac{p_{pool}\times (1-p_{pool})}{PV_{experiment}}) \\ ctp_{control} - ctp_{experiment} \sim N(0, p_{pool} \times (1-p_{pool})\times (\frac{1}{PV_{control}} + \frac{1}{PV_{experiment}})) \\ p_{pool} = \frac{total_{click}}{total_{pv}} \end{gather} \]

为什么将 \(p_{pool}\) 这么一个估计值作为其分布的参数?因为:

  1. 我们对于真实的 \(p\) 无从得知,便只能通过总体的概率作为其参数的估计。
  2. 在如此大样本的情况下,由中心极限定理也基本可知 \(p_{pool} \to p\) 极限逼近。
  3. 并且实验组和对照组都使用相同的 \(p_{pool}\) 作为参数,也就不会在此参数上引入变化。
sd_ctp = round(math.sqrt(total_ctp * (1-total_ctp) * (1/control_pv + 1/experiment_pv)), 4)
alpha_ctp = 0.05
print(f' 置信度为 99.5 的置信区间为:[{0 - round(get_z_score(1-alpha_click / 2)*sd_ctp,4)},{0 + round(get_z_score(1-alpha_click / 2)*sd_ctp,4)}]')
print(f'control_ctp - experiment_ctp = {round(control_ctp - experiment_ctp, 4)}')
置信度为 99.5 的置信区间为:[-0.0014,0.0014]
control_ctp - experiment_ctp = -0.0001

ctp 通过 Sanity Test

6.3 Examing effect Size

6.3.1 Gross Conversion

先对 Gross Conversion 转化率进行检验

理论准备:

  1. \(GC = \frac{erolled}{click}\)
  2. 需要计算的值:\(GC_{experiment} - GC_{control}\) 所服从的分布
  3. 原假设:\(GC_{experiment} = GC_{control}\); 备择假设:\(GC_{experiment} - GC_{control} \ge 0.01\)
  4. 原假设中 \(GC_{experiment} = GC_{control} = \frac{enrolled_{control} + enrolled_{experiment}}{click_{control} + click_{experiment}}\)

需要注意:在数据中,虽然 click 和 pageview 统计了很多,但是 enroll 和 payment 有缺失,在计算时只需要统计有 enroll 和 payment 记录的那些行即可

control = control.dropna()
experiment = experiment.dropna()
enroll_control = control['Enrollments'].sum()
enroll_experiment = experiment['Enrollments'].sum()

click_control_noNull = control['Clicks'].sum()
click_experiment_noNull = experiment['Clicks'].sum()

gc_control = round(enroll_control / click_control_noNull, 4)
gc_experiment = round(enroll_experiment / click_experiment_noNull, 4)
gc_pool = round((enroll_control + enroll_experiment) / (click_control_noNull + click_experiment_noNull), 4)

在原假设的前提下:

\[\begin{gather} GC_{experiment} - GC{control} \sim N(0, p_{pool} \times (1 - p_{pool}) \times (\frac{1}{click_{control}} + \frac{1}{click_{experiment}}) ) \end{gather} \]

sd_gc_diff = math.sqrt(gc_pool * (1-gc_pool) * ( 1/click_control_noNull + 1/click_experiment_noNull))
alpha_gc = 0.05
print(f' 置信度为 99.5 的置信区间为:[{0 - round(get_z_score(1-alpha_gc / 2)*sd_gc_diff,4)}, {0 + round(get_z_score(1-alpha_gc / 2)*sd_gc_diff,4)}]')
print(f'gc_experiment - gc_control = {round(gc_experiment - gc_control, 4)}')
置信度为 99.5 的置信区间为:[-0.0086, 0.0086]
gc_experiment - gc_control = -0.0206
  1. 在原假设的前提下,计算所得置信度为 99.5 的置信区间为 \([-0.0086, 0.0086]\), 而实际的差值为 \(-0.0206\),故显著拒绝原假设;
  2. \(GC_{experiment} - GC_{control} = -0.0206 > D_{min}\)(0.01),故具有实际意义

6.3.2 Net Conversion Test

payment_control = control['Payments'].sum()
payment_experiment = experiment['Payments'].sum()

nc_control = round(payment_control / click_control_noNull, 4)
nc_experiment = round(payment_experiment / click_experiment_noNull, 4)
nc_pool = round((payment_control + payment_experiment) / (click_control_noNull + click_experiment_noNull), 4)
sd_nc_diff = math.sqrt(nc_pool * (1-nc_pool) * ( 1/click_control_noNull + 1/click_experiment_noNull))
alpha_nc = 0.05
print(f' 置信度为 99.5 的置信区间为:[{0 - round(get_z_score(1-alpha_nc / 2)*sd_nc_diff,4)}, {0 + round(get_z_score(1-alpha_nc / 2)*sd_nc_diff,4)}]')
print(f'nc_experiment - nc_control = {round(nc_experiment - nc_control, 4)}')
置信度为 99.5 的置信区间为:[-0.0067, 0.0067]
nc_experiment - nc_control = -0.0049
  1. 在原假设的前提下,计算所得置信度为 99.5 的置信区间为 \([-0.0067, 0.0067]\), 而实际的差值为 \(-0.0049\),故无法拒绝原假设,差异不具有统计学上的显著性;
  2. \(NC_{experiment} - NC_{control} = -0.0049 < D_{min}\)(0.0075),故不具有实际意义

6.4 Double Check with Sign Test

In a sign test we get another angle at analyzing the results we got - we check if the trend of change we observed (increase or decrease) was evident in the daily data. We are goint to compute the metric's value per day and then count on how many days the metric was lower in the experiment group and this will be the number of succssesses for our binomial variable. Once this is defined we can look at the proportion of days of success out of all the available days.

连接方式:

  1. 内连接(inner):在两个表中搜索 指定的键 ,如果都具有指定的键对应的值,则将从两个表中搜索到的信息连接到一起
  2. 左连接(left): 以左边的 指定的键 去另一个表中查询对应键的数据,然后连接到左边的表后面(扩展部分)。如果没有找到,则扩展部分为 NuLL 值
  3. 右连接(right):逻辑和左连接一样
# 默认是 index 为 Key
full = control.join(other=experiment, how='inner', lsuffix='_cont', rsuffix='_expr')
full.info()
# 分别计算每一天的 GC
full['GC_cont'] = round(full['Enrollments_cont'] / full['Clicks_cont'], 4)
full['GC_expr'] = round(full['Enrollments_expr'] / full['Clicks_expr'], 4)
# 将 GC_cont > GC_expr 的行设为 1
full['GC_sign'] = np.where(full['GC_cont']<full['GC_expr'], 1, 0)

# 分别计算每一天的 NC
full['NC_cont'] = round(full['Payments_cont'] / full['Clicks_cont'], 4)
full['NC_expr'] = round(full['Payments_expr'] / full['Clicks_expr'], 4)
# 将 GC_cont > GC_expr 的行设为 1
full['NC_sign'] = np.where(full['NC_cont']<full['NC_expr'], 1, 0)

full.head()
Date_cont Pageviews_cont Clicks_cont Enrollments_cont Payments_cont Date_expr Pageviews_expr Clicks_expr Enrollments_expr Payments_expr GC_cont GC_expr GC_sign NC_cont NC_expr NC_sign
0 Sat, Oct 11 7723 687 134.0 70.0 Sat, Oct 11 7716 686 105.0 34.0 0.1951 0.1531 0 0.1019 0.0496 0
1 Sun, Oct 12 9102 779 147.0 70.0 Sun, Oct 12 9288 785 116.0 91.0 0.1887 0.1478 0 0.0899 0.1159 1
2 Mon, Oct 13 10511 909 167.0 95.0 Mon, Oct 13 10480 884 145.0 79.0 0.1837 0.1640 0 0.1045 0.0894 0
3 Tue, Oct 14 9871 836 156.0 105.0 Tue, Oct 14 9867 827 138.0 92.0 0.1866 0.1669 0 0.1256 0.1112 0
4 Wed, Oct 15 10014 837 163.0 64.0 Wed, Oct 15 9793 832 140.0 94.0 0.1947 0.1683 0 0.0765 0.1130 1
GC_x = full['GC_sign'].sum()
NC_x = full['NC_sign'].sum()
n = full.GC_cont.count()
print("No. of cases for GC:",GC_x,'\n',
      "No. of cases for NC:",NC_x,'\n',
      "No. of total cases",n)
No. of cases for GC: 4
 No. of cases for NC: 10
 No. of total cases 23

6.4.1 构建符号检验

组合数公式:\(C_n^k = \frac{n!}{k!(n-k)!}\)

我们首先假设(H0): \(GC_{cont} = GC_{expr}\), 则推导得:每一天的 \(P(GC_{cont} < GC{expr}) = 0.5\), 服从 \(p=0.5\) 的 0-1 分布
进而,我们统计事件 \(GC_{cont} < GC{expr}\) 发生的次数(k), \(k \sim B(n=23, p=0.5)\) 的伯努利分布
然后,我们计算在原假设条件下,观测到的 k 所对应的概率,从而根据概率,得知其显著性。

def get_prob(k,n):
    p = round(math.factorial(n)/(math.factorial(k)*math.factorial(n-k)) * math.pow(0.5,k)*math.pow(0.5, n-k), 4)
    return p
def get_2side_pvalue(k,n):
    p = 0
    for i in range(0,k+1):
        p += get_prob(i,n)
    return 2*p
print(f'GC sign test pvalue = {round(get_2side_pvalue(GC_x, n),4)}')
print(f'NC sign test pvalue = {round(get_2side_pvalue(NC_x, n),4)}')
GC sign test pvalue = 0.0026
NC sign test pvalue = 0.6774

显然,GC 通过符号检验, NC 则未通过,与 Z Test 检验结果一致

符号检验的意义:

  1. 最本质的意义:在原假设(两组在 metric 上相等,那么 实验组取值大于对照组的概率为 0.5)的情况下,发生 所观测到的事件以及比所观测到的事件更“离谱”的事件 的概率加起来有多小
  2. 在此处的意义:我们在上述原假设的情况下,计算观测事件及更离谱事件发生的概率,从而得到了其概率,对原假设进行检验

标签:control,AB,NC,round,experiment,GC,test,click
From: https://www.cnblogs.com/StephenSpace/p/17215914.html

相关文章

  • golang viper 处理TOML 特殊的arrar和array of table
    参考:https://github.com/spf13/viper/issues/213知识点:go类型断言tomlconfig:[src_isntances]#i=[{ip="dasds",port="asdas"},{ip="dffdafs",port="afasdsdas"}]i1=......
  • Cadence Virtuoso中动态链接到ADS不正常,Cannot find registration file ads,cdsenv to
      当启动virtuoso时会有如下警告,从而导致virtuoso动态链接到ADS工作不正常,比如仿真没有结果。解决方法:执行配置脚本,脚本位于$HPEESOF_DIR/bin/idfConfigCadence,直接执......
  • element-table 相关样式修改
    1.表格整体背景色修改/*表格整体背景色*/::v-deep.el-table,::v-deep.el-table__expanded-cell{background-color:transparent!important;}2.表格内tr......
  • Java容器之Hashtable源码分析
    一、概述Hashtable是一个比较古老的Map实现类,从它的名称就可以看得出来,因为没有遵循Java的语言规范。它和HashMap很像,同属于散列表,有以下特性:线程安全,这也估计算是唯一......
  • nacos报错 Caused by: com.alibaba.nacos.api.exception.NacosException: java.io.IOE
    麻麻劈,根据这个报错一顿ulimit -n 修改打开文件数,鸡儿报错一直在。 最终修改 vi/etc/sysctl.conf增加三项:fs.inotify.max_queued_events=32768fs.inotify.ma......
  • MIT 6.824-Lab1. MapReduce 实现思路
    参考资料MapReduce论文((20221029103443-4pqvf1n"Lecture-MapReduce"))Lab1实验文档Lab1实验文档译文任务需求在一个分布式存储系统上(实验是单机),实现coord......
  • Hashtable和Dictionary 的区别
    Hashtable和Dictionary都是.Net下的表示键值对的集合,那么我们在使用中该选择Hashtable还是Dictionary?下边我们看看他们之间的区别:1、Dictionary<K,V>在使用中是顺序存储的......
  • 使用iptabels将主机的所有流量转发至其他机器
    iptables是一个Linux内核中的包过滤工具,可以用来过滤、转发、修改、控制网络流量等。如果想要将主机的所有流量转发至其他机器,可以使用iptables进行配置。以下是具体步骤:......
  • lodop打印 table表格分页带表头页码
    lodop.PRINT_INIT("wageSalaryRetireRecordService");varstrBodyStyle="<style>"+document.getElementById("print_style").innerHTML+"</s......
  • php操作rabbitmq实例
    title:PHP使用RabbitMQ实例date:2021-03-2217:37:29tags:phpcategories:php消费者代码consumer.php <?php /** *CreatedbyPhpStorm. *User:wangyii.c......