方差分析(Analysis of Variance)¶
1 前言¶
上回书说到最小样本量的选择更侧重单样本或两样本均值和比率的检验。关于多个样本的均值检验可以另开一篇ANOVA方差分析(Analysis of Variance)来讲。新的一年从扶起去年的flag开始,所以我来填坑啦!
开始之前先思考一个问题:已经有了万能又好用的AB test,为什么还需要方差分析呢?答案很简单,在生产环境中,我们感兴趣的因变量通常会受到众多因素的影响。比如新药的有效性受到适应症、剂量、给药途径和方法、每日给药次数等条件的影响,比如商品销量受到广告投放,商品价格,淡旺季等等条件的影响。此外,每个影响因素可能有多个观测水平。比如网页的UI设计可能有ABCDEFG多个版本(毕竟听说同样是黑,也可能有五彩斑斓的黑)。当老板问你,这些因素对因变量是否有影响,以及因素的每一个水平的观测值是否有显著不同时,此时只侧重单因素两水平的AB test略显捉急,除非我们两两排列组合,测到天荒地老,然而多次检验会使得犯第一类错误的概率大大增加,且无法同时考虑所有的样本。这时候就需要ANOVA前来救场了。
2 原理介绍¶
在单因素的情况下,ANOVA方差分析实际上还是用来比较多个样本的均值是否相同/多个样本是否同分布,那为什么要叫方差分析呢?简单来说,它来源于对误差的分解。我们用样本的离差平方和来衡量总体的误差,总体误差SST(Sum of Square for Total)= 组内随机误差SSE(Sum of Square for Error)+ 组间误差SSA(Sum of Square for factor A)。统计量如下。SSE除以其自由度相当于每组内自身的方差,SSA除以其自由度相当于每组相对于总体的方差。当样本服从正态分布的时候,离差平方和服从卡方分布,因此该统计量相当于两个卡方分布之比,即为服从F分布。当F统计量越大时,说明分母小,组内方差小,都很集中;分子大,组间方差大,每组分隔较远,越趋向于拒绝多样本均值相同/同分布的原假设。
ANOVA方差分析有非常多的变化,可以根据因子数量分为单因素方差分析和多因素方差分析。当与实验设计DOE(Design of Experiment)联系起来时,则有完全随机设计,随机区组设计,拉丁方设计,正交设计等等多种形式。但大道至简,殊途同归。只要掌握了方差分析的基本逻辑,各种变化都可以信手拈来。这里主要按因子数量分类。
2.1 单因素方差分析(One Way ANOVA)¶
单因素方差分析只关心一个影响因素,但可能有多个观测水平。比如上面说到的UI设计的ABC三种版本对流量的影响,UI设计为一个因素,ABC三个版本为这个因素的三个观测水平。具体检验过程如下。
- 确立检验的原假设与备择假设:通常原假设为各组均值相同,备择假设为至少有一个不同。
- 计算F统计量:计算组内样本均值,总均值,各误差平方和及自由度,从而算出F统计量的值。
- 得到检验结论:将F统计量与查表得到的临界值相比,若统计量大于临界值,则可以拒绝原假设,认为总体均值存在差异。也可以计算出检验的P值,与事先设立的显著性水平α对比。若P值小于α,则可以拒绝原假设。
- 事后分析:即两两比较分析。当上一步中拒绝原假设后,说明各组均值至少有一个不同。此时再做Tukey's test或Bonferroni test两两比较,可知哪两组间存在显著差异。
举例如下,没有实验数据就随机生成模拟数据。
import numpy as np
#模拟一个单因素三水平的数据集,三水平分别为对照组和两个不同的实验组
#其中treat1和对照组均值非常接近,treat2则相差很大
df = {'control':list(np.random.normal(10,5,100)),
'treat1':list(np.random.normal(11,5,100)),
'treat2':list(np.random.normal(20,5,100))}
import pandas as pd
df = pd.DataFrame(df)
df.head()
#转换数据格式
df_melt = df.melt()
df_melt.head()
df_melt.columns = ['Treat','Value']
df_melt.head()
#箱线图可视化
import seaborn as sns
sns.boxplot(x='Treat',y='Value',data = df_melt)
from statsmodels.formula.api import ols
from statsmodels.stats.anova import anova_lm
# 此处举例为单因素方差分析,若为多因素,则Value~C(factor1)+C(factor2)...
# 若多因素之间有相互影响,则再加上交互项如C(factor1):C(factor2)
model = ols('Value~C(Treat)',data=df_melt).fit()
anova_table = anova_lm(model, typ = 2)
print(anova_table)
#各组样本数量相同,可用tukey test做两两比较分析
from statsmodels.stats.multicomp import MultiComparison
mc = MultiComparison(df_melt['Value'],df_melt['Treat'])
tukey_result = mc.tukeyhsd(alpha = 0.5)
print(tukey_result)
2.2 多因素方差分析(MANOVA)¶
多因素方差分析关心两个及以上影响因素,如上面说的商品销量受到价格和广告投放的影响。价格和广告为两个因素,每个因素各有若干个水平。我们想知道商品销量是否受其影响。
import numpy as np
#模拟一个两因素的数据集,其中一个为3水平,一个为5水平。
data = np.array([
[276, 352, 178, 295, 273],
[114, 176, 102, 155, 128],
[364, 547, 288, 392, 378]
])
df = pd.DataFrame(data)
df.index=pd.Index(['A1','A2','A3'],name='ad')
df.columns=pd.Index(['B1','B2','B3','B4','B5'], name='price')
print(df)
#转换数据格式
df1 = df.stack().reset_index().rename(columns={0:'value'})
print(df1)
from statsmodels.formula.api import ols
from statsmodels.stats.anova import anova_lm
# 两因素方差分析
# 若多因素之间有相互影响,则再加上交互项如C(factor1):C(factor2)
model = ols('value~C(ad) + C(price)', df1).fit()
anova_table = anova_lm(model)
print(anova_table)
#各组样本数量相同,可用tukey test做两两比较分析
from statsmodels.stats.multicomp import MultiComparison
mc = MultiComparison(df1['value'],df1['price'])
tukey_result = mc.tukeyhsd(alpha = 0.5)
print(tukey_result)
mc2 = MultiComparison(df1['value'],df1['ad'])
tukey_result2 = mc2.tukeyhsd(alpha = 0.5)
print(tukey_result2)
2.3 使用条件¶
方差分析的使用条件为: - 方差齐性:可用Barlett检验先检验方差齐性,在无法拒绝方差齐性的前提下,再做方差分析。若检验发现方差非齐性,可用Welch等方法校正后再做方差分析。 - 观测值独立同分布 - 观测值服从正态分布:若不正态,可以用非参数检验。
3 总结¶
对方差分析来说,只要明确了研究对象和试验设计方法,接下来的步骤就顺理成章非常顺滑。核心还是用F检验做组间方差和组内方差的比较。你学会了吗?