在实际业务中,我们经常会遇到频率类事件的假设检验,这类数据包括:留存率、点击率、转化率。我们甚至可以把大多数AB测试类的场景都理解为「频率的假设检验」。本文试图创建一个一般性的频率假设检验工具的EXCEL实现,并介绍其工作原理。文件参考这里

定义问题

其实,在具体工作中,我们都会遇到比例数据来作为指标衡量一个数据,可以大致将这些指标抽象成三类数据:正事件触发次数/用户数触发正事件的人数/人数正事件触发次数/总事件发生次数。我们在文章中将以「平均发生次数」(Average Count)、「转化率」(Transfer Rate)、「发生率」(Positive Rate)来表述这三类指标。

名称 平均发生次数 转化率 发生率
例子 人均成单量、人均点击量 留存率、成单转化率 按钮点击率、流程退出率
定义 正事件触发次数/用户数 触发正事件的人数/用户数 正事件触发次数/总时间发生次数
建议场景 单次触发具有实际意义;
和收入相关的内容;
较为综合的衡量产品的指标
与用户运营相关的指标;
评价用户粘性
判断某个功能好坏;
与产品细节优化相关
数据分布 指数分布为主,小概率为泊松分布 二项分布(Beta分布) 二项分布(Beta分布)

问题抽象

事实上,我们单纯从数学抽象上说,上面的比例数据,事实上可以抽象为两类问题,一个是「每个用户具有一个观测量」,比例事实上反应的是这个观测量的平均值;另一类则是「频率」,反应的是一个事件发生的概率(只是这个频率的维度是以事件为主还是用户为主)。我们本文就限定在「频率」这个抽象问题的范围内,考虑如何比较两组频率的差异。理解了这个抽象,我们可以同时分析次留、转化率、AB测试的数据。特别的,我们采用的统计工具在以下场合,会比直接比较两组的频率更有效:

  1. 当抽样数据过小时或极度不平衡时。譬如在产品仅在冷启动时期,这时候的流量相对较小,单纯比较频率容易有抽样误差;
  2. 快速决策的时候,特别地,需要决定何时终止比较的时候。譬如,在每单位时间成本极大的时候,如果进行AB测试,需要很快得到结果,终止测试。如果使用直接比较频率,我们往往无法做出何时终止测试的判断,下面的方法(特别是基于贝叶斯的方法)可以很快地在验证成功之后终止测试。

数学工具

首先,我们可以假设一个事件的发生频率为

\[f = X/N\]

其中, \(X\) 为正例发生次数,\(N\)则为事件发生总次数。譬如,在留存率(次留)中,\(X\)表示第二日使用产品的用户数,\(N\)表示计算当日的注册用户数。

我们很容易地可以做出假设:\(X\)属于二项分布,即:

\[X \sim B(N, p)\]

我们现在可以将其转化为两组二项数据的比较。

方案一:假设检验

这是最简单可以想到的方案。我们假设两组数据其参数分别为\(p_1\),\(p_2\)。则可以建立如下假设:

  • H0: \(p_1 = p_2\)
  • H1: \(p_1 \ne p_2\)

则统计量\(z\) 满足

\[z = \frac{\hat{p_1} - \hat{p_2}}{\sqrt{\hat{p}(1 - \hat{p})(\frac{1}{N_1} + \frac{1}{N_2})}}\]

其中,\(\hat{p} = \frac{N_1\hat{p_1} + N_2\hat{p_2}}{N_1 + N_2}\)

因为\(z \sim N(0, 1)\),我们就可以基于这个计算出相应的显著性值并进行比较。

可以在Excel的这部分看到结果,其中显著性大小我们这里分为0**, ***, **************五档,可以基于不同的数据量调整判断标准。

image-20210105112517589

方案二: 贝叶斯估计

在大多数场合下,特别是指数分布族内的分布中,我们一般会使用\(Beta(\alpha, \beta)\)分布作为先验分布,当然这么选择会有很多好处,首先:

  1. 当\(\alpha\),\(\beta\)足够大时,\(Beta(\alpha, \beta) \rightarrow B(\alpha + \beta, \frac{\alpha}{\alpha + \beta})\)。这样我们就可以刻画出以二项分布扩展的任何分布。
  2. 其次,当先验分布为\(Beta(\alpha, \beta)\),且新的观察量\(N\)中,有\(k\)个正例。则其后验分布可以算出为\(Beta(\alpha + k, \alpha + N - k)\),计算非常简单。
  3. \(Beta(1, 1)\)为均匀分布,非常方便的可以作为无信息的先验分布。

接下来,我们可以基于两组数据,来求出两个\(Beta\)分布,然后基于这两个\(Beta\)分布进行抽样,抽样的具体结果在Excel的这个位置:

image-20210105112617849

然后抽样结果的汇总数据,包括,每个例子的值还有分布,展示在这里:

image-20210105112714510

最后我们可以在这里看结果,这里提供以下指标,就是两个比例的抽样均值,还有就是给出两组数据之间差值正负的比例(\(P(A>B)\)、\(P(B \ge A)\)这两项),差值的相关信息(包括平均数、方差、中位数)。基于这些量,我们就能很容易做出两组数据何者更好的

image-20210105112753093

AB测试的一个动态推广

示例可以参考这里

AB测试的时候,我们很想很快知道测试结果,因为某些测试本身可能会影响到功能、收入等情况,这时候,我们就需要知道何时终止测试。而上面的贝叶斯的方案,可以给我们提供一个解决这一问题的发想。

首先,我们要把AB测试的数据结果看成两(或多)组时间序列数据,在快速测试时,我们可能使用按分钟的维度来监控这两组数据。譬如我们现在要测试两个按钮设计的点击率,则需要统计每一分组内,每个按钮点击次数和未点击次数,譬如生成下列数据,一个是0.62概率一个0.65,我们生成100个时间段的数据,且故意让两个数据很接近而且抽样非常不平均。

import numpy as np
from scipy.stats import binom, beta
from plotnine import *
from itertools import accumulate
import pandas as pd


n1, p1 = 10000, 0.62
n2, p2 = 10000, 0.65
seed_a = binom.rvs(1, p1, size=2000)
seed_b = binom.rvs(1, p2, size=10000)

np.random.shuffle(a)
np.random.shuffle(b)
a = [(sum(i==1), sum(i==0)) for i in np.array_split(seed_a, 100)]
b = [(sum(i==1), sum(i==0)) for i in np.array_split(seed_b, 100)]

然后,我们主要通过\(max(P(p_a > p_b), P(p_a \le p_b))\),来判断是不是具有显著的差异。显然,当这个值越接近于1,表示这抽样数据里面两个组的数据有差别的可能性越大,我们就可以基于此来判断是否可以终止实验。核心的抽样算法实现如下,其中beta.rvs(a, b, size=n)就表示生成n个beta分布的数据。然后我们可以应用贝叶斯的方法,很快地随着每批数据进来快速地产生新的后验概率并基于此抽样。

def gennerate_avg(n=100000):
    def helper(row):
        res = np.sum(
            beta.rvs(row['a_x'] + 1, row['a_y'] + 1, size=n) >
            beta.rvs(row['b_x'] + 1, row['b_y'] + 1, size=n)
        ) / n
        return res if res >= 1 - res else 1 - res
    return helper

最后,我们就可以实时地展示两幅图,来动态判断是不是有把握可以终止实验,做出判断了。第一幅是两个点击率随数据进来后,渐渐趋于稳定的比较图,这张图主要展示,此时a、b组点击率的变化。只有当a、b组点击率不发生明显波动时,我们才能做出判断。这个是防止我们过早地终止实验。其次,这张图也一定程度直观告诉我们,两个点击率哪个大哪个小。

image-20210105144846253

第二幅图则是\(max(P(p_a > p_b), P(p_a \le p_b))\)的演化图,它衡量的是两组数具有差异的可能性。我们可以添加我们能容忍错误的可能性,比如下图的绿线表示我们的容忍底线0.999,即我们保证抽样的99.9%的数据都显示出有一组大于另一组的差异时,我们就可以终止实验了。比如次例子中,我们大致在第60分钟时,就可以终止实验,而不需要积累大量数据。

image-20210105150006274