1. 什么是t检验?

t检验是统计学中最常用的假设检验方法之一,主要用于比较两组数据的均值是否存在显著差异。想象一下,你买了一杯标称500ml的奶茶,喝了几口后怀疑分量不足,这时就可以用t检验来判断奶茶的实际容量是否真的少于500ml。

t检验的核心思想是通过样本数据推断总体情况。它基于t分布理论,特别适合小样本(通常n<30)且总体标准差未知的情况。在实际应用中,t检验主要有三种类型:

  • 单样本t检验:比较样本均值与已知总体均值(如奶茶容量与标称值)
  • 独立样本t检验:比较两个独立组的均值(如男女生的考试成绩)
  • 配对样本t检验:比较同一组对象在不同条件下的均值(如服药前后的血压值)

2. 准备工作:Python环境与数据

2.1 安装必要库

在开始前,确保已安装以下Python库:

pip install numpy pandas scipy matplotlib

2.2 模拟数据集

我们创建三个典型场景的数据:

import numpy as np
import pandas as pd

# 单样本数据:饮料净含量(ml)
drinks = np.array([498, 502, 495, 503, 497, 501, 499, 504, 496, 502])

# 独立样本数据:A/B两组测试成绩
group_a = np.array([78, 85, 92, 88, 76])
group_b = np.array([82, 89, 85, 91, 87, 84])

# 配对样本数据:减肥前后体重(kg)
before = np.array([68, 72, 65, 70, 75])
after = np.array([65, 70, 63, 68, 72])

3. 单样本t检验实战

3.1 检验步骤

假设饮料标称500ml,我们想检验实际容量是否不足:

  1. 假设设立

    • H₀(原假设):μ = 500ml
    • H₁(备择假设):μ < 500ml(单侧检验)
  2. 正态性检验

from scipy import stats
print(stats.shapiro(drinks))  # p值>0.05则符合正态分布
  1. 执行检验
t_stat, p_value = stats.ttest_1samp(drinks, popmean=500, alternative='less')
print(f"t统计量: {t_stat:.3f}, p值: {p_value:.4f}")

3.2 结果解读

当输出结果为:

t统计量: -0.837, p值: 0.2162

由于p值>0.05,不能拒绝原假设,说明没有足够证据表明饮料容量不足500ml。

4. 独立样本t检验实战

4.1 方差齐性检验

比较A/B两组成绩前,先检验方差是否相等:

levene_test = stats.levene(group_a, group_b)
print(f"方差齐性检验p值: {levene_test.pvalue:.3f}")

4.2 执行检验

根据方差齐性结果选择参数:

if levene_test.pvalue > 0.05:
    t_result = stats.ttest_ind(group_a, group_b, equal_var=True)
else:
    t_result = stats.ttest_ind(group_a, group_b, equal_var=False)
print(f"t统计量: {t_result.statistic:.3f}, p值: {t_result.pvalue:.3f}")

4.3 效应量计算

除了p值,还应报告效应量:

def cohen_d(x, y):
    nx, ny = len(x), len(y)
    pooled_std = np.sqrt(((nx-1)*np.std(x)**2 + (ny-1)*np.std(y)**2)/(nx+ny-2))
    return (np.mean(x)-np.mean(y))/pooled_std

print(f"Cohen's d: {cohen_d(group_a, group_b):.3f}")

5. 配对样本t检验实战

5.1 数据预处理

计算前后差值并检查正态性:

diffs = after - before
print(stats.shapiro(diffs))

5.2 执行检验

t_result = stats.ttest_rel(before, after)
print(f"t统计量: {t_result.statistic:.3f}, p值: {t_result.pvalue:.4f}")

5.3 可视化展示

import matplotlib.pyplot as plt
plt.figure(figsize=(10,5))
plt.plot([1,2], [before.mean(), after.mean()], 'ro-')
plt.errorbar([1,2], [before.mean(), after.mean()], 
             yerr=[before.std(), after.std()], fmt='o')
plt.xticks([1,2], ["减肥前", "减肥后"])
plt.ylabel("平均体重(kg)")
plt.show()

6. 常见问题与解决方案

6.1 正态性不满足怎么办?

当数据非正态时:

  1. 尝试数据转换(如对数变换)
  2. 使用非参数检验(如Wilcoxon检验)
# 单样本替代方案
stats.wilcoxon(drinks - 500)
# 独立样本替代方案
stats.mannwhitneyu(group_a, group_b)

6.2 样本量极小时

当n<15时:

  • 增加样本量
  • 使用更保守的显著性水平(如α=0.01)
  • 考虑贝叶斯t检验

6.3 多重比较问题

进行多次检验时,需校正p值:

from statsmodels.stats.multitest import multipletests
pvals = [0.03, 0.01, 0.005]
print(multipletests(pvals, method='bonferroni')[1])  # 校正后p值

7. 完整案例演示

7.1 业务场景

某电商想验证:

  1. 新页面转化率是否高于旧页面(独立样本)
  2. 用户周均访问次数是否大于3次(单样本)
  3. 促销活动前后客单价变化(配对样本)

7.2 Python实现

# 1. 独立样本检验
old_page = np.random.normal(0.15, 0.03, 100)
new_page = np.random.normal(0.18, 0.04, 120)
print(stats.ttest_ind(new_page, old_page, alternative='greater'))

# 2. 单样本检验
visits = np.random.poisson(3.5, 50)
print(stats.ttest_1samp(visits, popmean=3, alternative='greater'))

# 3. 配对检验
pre_sale = np.random.lognormal(3.5, 0.3, 30)
post_sale = pre_sale * 1.1 + np.random.normal(0, 0.1, 30)
print(stats.ttest_rel(post_sale, pre_sale))

8. 进阶技巧

8.1 功效分析

确定所需样本量:

from statsmodels.stats.power import TTestIndPower
effect_size = 0.5
alpha = 0.05
power = 0.8
analysis = TTestIndPower()
sample_size = analysis.solve_power(effect_size, power=power, alpha=alpha)
print(f"所需样本量: {sample_size:.0f}")

8.2 贝叶斯t检验

import pymc3 as pm
with pm.Model():
    mu = pm.Normal('mu', mu=0, sd=10)
    obs = pm.Normal('obs', mu=mu, sd=1, observed=diffs)
    trace = pm.sample(2000)
pm.plot_posterior(trace)

在实际项目中,t检验结果需要结合业务背景解读。比如p=0.06时,虽然统计学上不显著,但从业务角度可能仍值得关注。建议同时报告置信区间:

ci = stats.t.interval(0.95, len(drinks)-1, loc=drinks.mean(), scale=stats.sem(drinks))
print(f"95%置信区间: ({ci[0]:.2f}, {ci[1]:.2f})")

更多推荐