方差分析
1 方差分析(F检验)
可以检验两组或者多组样本的均值是否具备显著性差异;由四个前提假设:
- 随机性:样本是随机采样的
- 独立性:来自不同组的样本是相互独立的;
- 正态分布性:组内样本都来自一个正太分布;
- 方差齐性:不同组的方差相等或相近;
方差分析的核心思想®:差异是不是显著性,关键是要看这个差异是采样的偶然性引起的,还是分布本身引起的;
2 *度
- 采样中能够*变化的数据个数;
- 对于一组包含n个数据的采样来说,如果方差是一个固定值,那么只有n-1个数据可以*变化,最后一个数的取值是给定的方差和其他n-1个数据决定的。而不是由它随意变化的;
3 例子
- 这里,我使用之前提到的 A/B 测试案例,通过方差分析来检验多种算法所产生的用户转化率有没有显著性差异。
- 我们把“转化率”称为“因变量”,把“算法”称为“因素”。这里我们只有算法一个因素,所以所进行的方差分析是单因素方差分析;
- 在方差分析中,因素的取值是离散型的,我们称不同的算法取值为水平;。如果我们比较算法 a 和 b,那么 a 和 b 就是算法这个因素的水平;
我们假设只有两种算法 a 和 b 参与了 A/B 测试。为了检验这些算法导致的转化率,是不是存在显著的差异,我们进行一个为期 10 天的测试,每天都为每种算法获取一个转化率,如下表:
- 如果我们把每种算法导致的转化率看作一个数据分布,那么方差分析要解决的问题就是:这两个转化率分布的均值,是不是相等。如果我把两种数据分布的均值记做μ1 和μ2,那么原假设 H0就是μ1=μ2。而对立假设 H1 就是μ1 <> μ2。
我们就算了**SST、SSM 和 SSE。**计算公式如下:
SST 表示所有采样数据的因变量方差;
由此可以看出,SST 是由 SSM 和 SSE 构成的。
如果在 SST 中,SSM 的占比更大,那么说明因素对因变量的差异具有更显著的影响。
如果 SSE 的占比更大,那么说明采样误差对因变量的差异具有更显著的影响。
我们使用这两部分的比例来衡量显著性,并把这个比例称为 F 值.具体公式如下:
在这个公式中,s是水平的个数,n为样本的总数量,s-1为分布的*度;n-s为误差的*度;
在我们的案例中,F=(0.00018/(2-1))/(0.01652/(20-2))=0.196125908。有了 F 值,我们需要根据 F 检验值的临界表来查找对应的的P 值。我列出了这张表的常见内容,你可以看看。
- 通过这张表以及 n 和 m 的值,我们可以找到,在显著性水平α为 0.05 的时候,F 值的临界值。
- 如果大于这个临界值,那么 F 检验的 P 值就会小于显著性水平α,证明差异具有显著性。
- 分析结果如下:
在咱们的案例中,n=20,m=s-1=1,所以对应的 F 值4.414。而我们计算得到的 F 值为 0.196,远远小于 4.414,因此说明差异没有显著性。
虽然算法 a 所导致的平均转化率要比算法 b 的相对高出约2%(要注意,2% 的相对提升在转化率中已经算很高了),但是由于差异没有显著性,所以这个提升的偶然性很大,并不意味着算法 a 比算法 b 更好。
4 使用 Python 代码进行验证
除了手动计算外,我们可以用python的代码来验证手动计算的正确性。
首先,我们要确保自己安装了python的扩展包statsmodels,如果没有安装采用下面的命令:
pip install -U statsmodels
我们可以把下列数据输入一个 oneway.csv 文件。
algo,ratio
a,0.29
a,0.36
a,0.32
a,0.29
a,0.34
a,0.24
a,0.27
a,0.29
a,0.31
a,0.27
b,0.29
b,0.33
b,0.31
b,0.30
b,0.31
b,0.26
b,0.25
b,0.30
b,0.28
b,0.29
安装完了 statsmodels,并建立了数据文件 oneway.csv,我们就可以运行下面这段 Python 代码来进行 F 检验了。
import pandas as pd
from statsmodels.formula.api import ols
from statsmodels.stats.anova import anova_lm
import scipy.stats as ss
# 读取数据,d1 对应于算法 a,d2 对应于算法 b
df = pd.read_csv("/Users/shenhuang/Data/oneway.csv") # 设置为你自己的文件路径
d1 = df[df['algo'] == 'a']['ratio']
d2 = df[df['algo'] == 'b']['ratio']
# 检测两个水平的正态性
print(ss.normaltest(d1))
print(ss.normaltest(d2))
# 检测两个水平的方差齐性
args = [d1, d2]
print(ss.levene(*args))
# F 检验的第一种方法
print(ss.f_oneway(*args))
# F 检验的第二种方法
model = ols('ratio ~ algo', df).fit()
anovat = anova_lm(model)
print(ano
我们假设用于 A/B 测试的两个算法是相互独立且随机的,所以这里只检测了正态分布性和方差齐性。
其中,ss.normaltest 分别测试了两个水平的正态分布:
NormaltestResult(statistic=0.16280747339563784, pvalue=0.9218214431590781)
NormaltestResult(statistic=0.4189199849120419, pvalue=0.8110220857858036)
ss.normaltest 的原假设是数据符合正态分布,两次验 P 值都是远远大于 0.05 的,所以原假设成立,这两者都符合正态分布;
而 ss.levene 分析了两者的方差齐性,同样 P 值都都是远远大于 0.05,因此符合方差齐的前提。
LeveneResult(statistic=0.7944827586206901, pvalue=0.38450823419725666)
ss.f_oneway 和 anova_lm 都可以进行F 检验。ss.f_oneway 给出的结果比较简洁。
F_onewayResult(statistic=0.19612590799031476, pvalue=0.663142430745588)
而 anova_lm 提供了更多的信息,但是两种 F 检验函数都证明了我们之前的手动推算结果是正确的。
df sum_sq mean_sq F PR(>F)
algo 1.0 0.00018 0.000180 0.196126 0.663142
Residual 18.0 0.01652 0.000918 NaN NaN
5 总结
方差分析可以帮助我们检测差异的显著性,它分析的内容是受一个或多个因素影响的因变量在不同水平分组的差异。不过单因素的方差分析要去因变量属于正态分布,并具有方差齐性。如果因变量的分布明显非正态分布,或者方差的差异很显著,那么我们就不能直接使用这种方法;
对于方差不齐的情况,我们可以选择适当的函数,例如对数,倒数等等,对原始数据进行转换,直到方差齐性显著;或者剔除明显属于”均值±标准差"之外的数据。
对于非正态分布的数据,我们也可以使用非参数的分析;非参数检验是在总体的方差知道很少的情况下,利用样本的数据对总体的分布形态等进行推断的方法。名字中的“非参数”的由来,就是因为这种检验方法在推断过程中不涉及有关总体分布的参数,而是只进行分布位置,分布形状之间的比较,因此不受总体分布的限定,使用范围比较广,常见的非参数检验包括二项分布检验。k-s检验,卡方检验等等;
上一篇: 方差分析