ThinkStats2 项目中的假设检验实践指南
假设检验基础概念
假设检验是统计学中用于判断观察到的差异是否具有统计学意义的重要方法。在ThinkStats2项目中,作者Allen Downey通过实际案例展示了如何进行假设检验。
核心思想
假设检验的基本流程是:
- 观察两组数据之间的差异
- 建立零假设(null hypothesis),即假设两组数据实际上没有差异
- 通过模拟零假设来评估观察到的差异是否可能由随机因素导致
实际案例:初生儿与其他婴儿的比较
数据准备
项目使用了美国国家家庭成长调查(NSFG)的数据,比较初生儿(first babies)和其他婴儿(others)在怀孕周期和出生体重等方面的差异。
live, firsts, others = first.MakeFrames()
group1 = firsts.prglngth # 初生儿怀孕周期
group2 = others.prglngth # 其他婴儿怀孕周期
检验统计量
定义检验统计量为两组均值的绝对差异:
def TestStatistic(data):
group1, group2 = data
return abs(group1.mean() - group2.mean())
实际观察到的差异为0.078周,约13小时。
零假设模拟
通过混合两组数据并随机重排来模拟零假设:
n, m = len(group1), len(group2)
pool = numpy.hstack((group1, group2))
def RunModel():
numpy.random.shuffle(pool)
return pool[:n], pool[n:]
计算p值
进行1000次模拟,计算检验统计量大于等于实际观察值的比例:
test_stats = numpy.array([TestStatistic(RunModel()) for i in range(1000)])
pvalue = sum(test_stats >= actual) / len(test_stats)
本例中p值约为15%,说明观察到的差异可能由随机因素导致。
假设检验的类实现
ThinkStats2项目将假设检验抽象为一个类,便于复用和扩展:
class HypothesisTest:
def __init__(self, data):
self.data = data
self.MakeModel()
self.actual = self.TestStatistic(data)
self.test_stats = None
def PValue(self, iters=1000):
self.test_stats = [self.TestStatistic(self.RunModel())
for _ in range(iters)]
return sum(self.test_stats >= self.actual) / iters
# 抽象方法需要子类实现
def TestStatistic(self, data): raise NotImplementedError()
def MakeModel(self): pass
def RunModel(self): raise NotImplementedError()
均值差异检验的实现
class DiffMeansPermute(HypothesisTest):
def TestStatistic(self, data):
group1, group2 = data
return abs(group1.mean() - group2.mean())
def MakeModel(self):
group1, group2 = self.data
self.n, self.m = len(group1), len(group2)
self.pool = numpy.hstack((group1, group2))
def RunModel(self):
numpy.random.shuffle(self.pool)
return self.pool[:self.n], self.pool[self.n:]
使用示例
data = (firsts.prglngth, others.prglngth)
ht = DiffMeansPermute(data)
p_value = ht.PValue(iters=1000)
print('p-value =', p_value)
扩展应用:标准差差异检验
通过继承DiffMeansPermute类,可以轻松实现标准差差异检验:
class DiffStdPermute(DiffMeansPermute):
def TestStatistic(self, data):
group1, group2 = data
return abs(group1.std() - group2.std())
p值操纵(p-hacking)问题
项目还演示了p值操纵的危险性:如果进行足够多次的测试,总能找到"显著"的结果。
模拟实验
def run_a_test(sample_size=100):
group1 = numpy.random.normal(100, 15, size=sample_size)
group2 = numpy.random.normal(100, 15, size=sample_size)
ht = DiffMeansPermute((group1, group2))
return ht.PValue(iters=200)
# 进行100次实验
p_values = numpy.array([run_a_test() for _ in range(100)])
sum(p_values < 0.05) # 约5%会出现假阳性
实际应用建议
- 预先确定研究假设和检验方法,避免数据驱动型的假设
- 理解p值的含义:p<0.05并不意味着效应量大或结果重要
- 考虑效应量的大小和实际意义
- 对多重检验进行校正
- 报告所有进行的检验,而不仅是显著的结果
通过ThinkStats2项目的这些示例,我们可以更好地理解假设检验的实际应用和潜在陷阱。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考