R: R 假设检验
最后更新:2026-08-26
上一课我们学了概率分布——理论。这一课进入假设检验——用样本推断总体。这是统计学的核心:广告说"提升 20% 销量"是真的还是忽悠?两组数据差异是偶然还是必然?R 用 4 行代码回答。
读完这一课你就能用 R 做:t 检验(均值比较)、比例检验(合格率比较)、卡方检验(独立性)、方差分析(多组比较)。
1. 你将学到
- 假设检验 5 步流程(原假设/备择/统计量/p 值/决策)
- t.test 单样本/双样本/配对
- prop.test 比例检验
- chisq.test 卡方检验(独立性/拟合优度)
- aov 方差分析 ANOVA
- 非参数检验 wilcox.test
- p 值解读与常见陷阱
2. 一个 A/B 测试的故事
(1) 痛点:广告有用吗?
Bob做了 A/B 测试:
- A 组(旧广告):1000 人,转化 80 人(8%)
- B 组(新广告):1000 人,转化 100 人(10%)
manager问:"2% 的差异是真的还是偶然?"
(2) R 的解法
R
# 两比例检验
prop.test(c(80, 100), c(1000, 1000))
# 2-sample test for equality of proportions
# X-squared = 2.46, df = 1, p-value = 0.117
# 结论:p > 0.05,差异**不显著**(可能是偶然)
1 行代码 → p 值 → 决策。
3. 假设检验 5 步流程
(1) 5 步流程
graph TB
A[1. 提出假设] --> B[2. 计算统计量]
B --> C[3. 计算 p 值]
C --> D[4. 决策]
D --> E[5. 报告]
A --> A1["H0 原假设<br/>H1 备择假设"]
B --> B1["t/z/卡方/F"]
C --> C1["P 数据像 H0 一样极端的概率"]
D --> D1["p < 0.05 → 拒绝 H0"]
E --> E1["报告 p 值 + 效应量 + 置信区间"]
style A fill:#fff3cd
style B fill:#cce5ff
style C fill:#d4edda
style D fill:#f8d7da
style E fill:#e1d4ff
(2) 关键概念
| 概念 | 含义 |
|---|---|
| H0(原假设) | 默认假设:两组无差异(差异 = 偶然) |
| H1(备择假设) | 真正想证明的:两组有差异 |
| 统计量 | 衡量"差异多大"的数字(t、z、χ²、F) |
| p 值 | 在 H0 为真时,观察到当前/更极端结果的概率 |
| α(显著性水平) | p 值的阈值,常用 0.05 |
| 拒绝 H0 | p < 0.05,差异统计显著 |
| 不拒绝 H0 | p ≥ 0.05,不能说有差异(≠ 无差异) |
⚠️ 关键:"不拒绝 H0 ≠ 接受 H0"。p > 0.05 只表示"证据不足",不是说"两组真的相等"。
4. t.test():均值比较
(1) 3 种 t 检验
| 类型 | 场景 | R 语法 |
|---|---|---|
| 单样本 | 1 组 vs 已知值 | t.test(x, mu = 0) |
| 双样本独立 | 2 组独立样本 | t.test(x, y) |
| 配对样本 | 同一对象前后测 | t.test(x, y, paired = TRUE) |
(2) 单样本 t 检验
R
# 例:产品重量标准 100g,测 10 个产品
weights <- c(98, 102, 99, 101, 100, 97, 103, 99, 101, 100)
t.test(weights, mu = 100)
# One Sample t-test
# t = 0, df = 9, p-value = 1
# 95% CI: [98.7, 101.3]
# mean of x = 100
# 结论:p = 1,**不拒绝 H0**,均值等于 100g
(3) 双样本独立 t 检验
R
# 例:A/B 测试两组转化时间
group_a <- c(12, 15, 14, 13, 16, 14, 15, 13, 14, 15)
group_b <- c(10, 11, 12, 13, 11, 10, 12, 11, 13, 12)
t.test(group_a, group_b)
# Welch Two Sample t-test
# t = 5.32, df = 14.6, p-value = 0.0001
# 95% CI: [1.36, 3.24]
# 结论:p < 0.05,**拒绝 H0**,A 组显著慢于 B 组
(4) 配对 t 检验
R
# 例:同一组患者用药前 vs 用药后
before <- c(180, 175, 190, 170, 185)
after <- c(165, 160, 175, 160, 170)
t.test(before, after, paired = TRUE)
# Paired t-test
# t = 8.5, df = 4, p-value = 0.001
# 结论:p < 0.05,**显著下降**(药物有效)
(5) 关键参数
| 参数 | 含义 | 默认 |
|---|---|---|
mu |
单样本的已知值 | 0 |
paired |
是否配对 | FALSE |
var.equal |
等方差假设 | FALSE(Welch) |
alternative |
备择方向 | "two.sided" |
conf.level |
置信水平 | 0.95 |
R
# 单侧检验(右侧)
t.test(x, mu = 100, alternative = "greater")
# 单侧检验(左侧)
t.test(x, mu = 100, alternative = "less")
5. prop.test():比例检验
(1) 单比例检验
R
# 例:产品历史合格率 95%,现在抽 100 个有 92 个合格
prop.test(92, 100, p = 0.95)
# 1-sample proportions test
# X-squared = 1.27, df = 1, p-value = 0.26
# 结论:p > 0.05,合格率**未显著下降**
(2) 双比例检验(A/B 测试核心)
R
# 例:A 组 1000 人转化 80,B 组 1000 人转化 100
prop.test(c(80, 100), c(1000, 1000))
# 2-sample test for equality of proportions
# X-squared = 2.46, df = 1, p-value = 0.117
# 95% CI: [-0.046, 0.006]
# 结论:p > 0.05,**差异不显著**(可能是偶然)
(3) prop.test vs chisq.test
prop.test(c(s1, s2), c(n1, n2))=chisq.test(matrix(c(s1, n1-s1, s2, n2-s2), 2))prop.test加了连续性校正(推荐)
6. chisq.test():卡方检验
(1) 2 大用途
| 用途 | 场景 | 公式 |
|---|---|---|
| 拟合优度 | 观察 vs 期望 | chisq.test(observed) |
| 独立性 | 2 个分类变量相关? | chisq.test(table(x, y)) |
(2) 拟合优度检验
R
# 例:骰子公平性测试(投 60 次)
observed <- c(8, 12, 10, 11, 9, 10) # 6 个面的次数
expected <- rep(10, 6) # 期望均匀
chisq.test(observed, p = expected / sum(expected))
# Chi-squared test
# X-squared = 1.2, df = 5, p-value = 0.945
# 结论:p > 0.05,骰子**公平**(不拒绝均匀假设)
(3) 独立性检验
R
# 例:性别 vs 购买行为
gender <- c("男", "男", "女", "女", "男", "女", "男", "女")
purchase <- c("买", "不买", "买", "买", "不买", "买", "买", "不买")
tab <- table(gender, purchase)
print(tab)
# 不买 买
# 男 1 3
# 女 1 3
chisq.test(tab)
# X-squared = 0, df = 1, p-value = 1
# 结论:p > 0.05,性别与购买**无关**
# 注意:任何 2x2 表期望频数 < 5 用 Fisher 精确检验
fisher.test(tab)
(4) 期望频数要求
R
# 卡方检验要求:每个单元格期望频数 ≥ 5
# 不满足时用 Fisher 精确检验
result <- chisq.test(tab)
result$expected # 查看期望频数
7. aov() 方差分析(ANOVA)
(1) 适用场景
3 组及以上均值的比较(t 检验只能 2 组)。
(2) 实战
R
# 例:3 种肥料对作物产量的影响
fertilizer <- c(rep("A", 10), rep("B", 10), rep("C", 10))
yield <- c(20, 22, 21, 19, 23, 20, 21, 22, 19, 20, # A
25, 26, 24, 27, 25, 26, 27, 25, 24, 26, # B
18, 19, 17, 18, 19, 20, 19, 18, 19, 20) # C
df <- data.frame(fertilizer, yield)
# 单因素 ANOVA
model <- aov(yield ~ fertilizer, data = df)
summary(model)
# Df Sum Sq Mean Sq F value Pr(>F)
# fertilizer 2 220.0 110.0 91.7 <2e-16 ***
# Residuals 27 32.4 1.2
# 结论:p < 0.05,3 种肥料**显著不同**
# 事后检验:Tukey HSD
TukeyHSD(model)
# diff lwr upr p adj
# B-A 5.0 3.91 6.09 0.000
# C-A -1.5 -2.59 -0.41 0.005
# C-B -6.5 -7.59 -5.41 0.000
8. wilcox.test() 非参数检验
(1) 何时用?
- 数据不正态(不能 t 检验)
- 样本量小(n < 30)
- 有极端离群点
- 顺序数据(如"优/良/中/差")
(2) 实战
R
# 配对非参数(Wilcoxon signed-rank)
before <- c(180, 175, 190, 170, 185)
after <- c(165, 160, 175, 160, 170)
wilcox.test(before, after, paired = TRUE)
# V = 15, p-value = 0.0625
# 结论:p > 0.05(不显著),但样本小
# 独立非参数(Mann-Whitney U)
group_a <- c(12, 15, 14, 13, 16)
group_b <- c(10, 11, 12, 13, 11)
wilcox.test(group_a, group_b)
# W = 25, p-value = 0.028
# 结论:p < 0.05,差异显著
9. p 值解读与陷阱
(1) p 值正确理解
| 解读 | 说明 |
|---|---|
| ✅ 正确 | 在 H0 为真时,观察到当前/更极端结果的概率 |
| ❌ 错误 | "H0 为真的概率" |
| ❌ 错误 | "差异是因为偶然的概率" |
| ❌ 错误 | "差异的强度" |
(2) 5 大常见陷阱
graph TB
A[p 值陷阱] --> B[p-hacking<br/>多次试到 p<0.05]
A --> C[样本量大 p 必小<br/>需看效应量]
A --> D[p<0.05 不等于有用<br/>看 effect size]
A --> E[不拒绝 ≠ 接受 H0]
A --> F[显著性 ≠ 实际意义]
style A fill:#fff3cd
style B fill:#f8d7da
style C fill:#cce5ff
style D fill:#d4edda
style E fill:#e1d4ff
style F fill:#ffe1d4
(3) 效应量(effect size)
只看 p 值不够,要看效应量——差异有多大:
| 检验 | 效应量 |
|---|---|
| t 检验 | Cohen's d = (m1 - m2) / s_pooled |
| ANOVA | η²(eta squared) |
| 卡方 | Cramér's V |
| 相关 | r(相关系数) |
R
# Cohen's d 计算
cohens_d <- function(x, y) {
n1 <- length(x)
n2 <- length(y)
s_pooled <- sqrt(((n1-1)*var(x) + (n2-1)*var(y)) / (n1 + n2 - 2))
(mean(x) - mean(y)) / s_pooled
}
| Cohen's d | 含义 |
|---|---|
| 0.2 | 小效应 |
| 0.5 | 中效应 |
| 0.8 | 大效应 |
10. 完整示例:A/B 测试 + 多组比较
下面是一个完整工作流示例,把本课所有假设检验知识串起来。
▶ 示例:营销活动效果全面检验
R
📖 仅展示
# ============================================
# 营销活动效果全面检验
# 功能:t 检验 / 比例检验 / ANOVA 综合
# ============================================
set.seed(42)
# 1. A/B 测试转化时间
group_a <- rnorm(50, mean = 15, sd = 3) # 原页面
group_b <- rnorm(50, mean = 13, sd = 3) # 新页面
cat("=== A/B 测试:转化时间 ===\n")
cat("A 组均值:", round(mean(group_a), 2), "秒\n")
cat("B 组均值:", round(mean(group_b), 2), "秒\n")
cat("差异:", round(mean(group_a) - mean(group_b), 2), "秒\n\n")
# 2. t 检验
t_result <- t.test(group_a, group_b)
print(t_result)
cat("\n")
# 3. Cohen's d
n1 <- length(group_a)
n2 <- length(group_b)
s_pooled <- sqrt(((n1-1)*var(group_a) + (n2-1)*var(group_b)) / (n1+n2-2))
cohens_d <- (mean(group_a) - mean(group_b)) / s_pooled
cat("Cohen's d(效应量):", round(cohens_d, 3), "\n")
cat("效应大小:", ifelse(abs(cohens_d) > 0.8, "大",
ifelse(abs(cohens_d) > 0.5, "中", "小")), "\n\n")
# 4. A/B 测试转化率
convert_a <- 80
convert_b <- 100
visitors_a <- 1000
visitors_b <- 1000
cat("=== A/B 测试:转化率 ===\n")
cat("A 组转化率:", round(convert_a / visitors_a * 100, 2), "%\n")
cat("B 组转化率:", round(convert_b / visitors_b * 100, 2), "%\n\n")
# 5. 比例检验
prop_result <- prop.test(c(convert_a, convert_b),
c(visitors_a, visitors_b))
print(prop_result)
cat("\n")
# 6. 3 种营销策略对比(ANOVA)
strategy <- c(rep("邮件", 20), rep("短信", 20), rep("推送", 20))
sales <- c(rnorm(20, 100, 15),
rnorm(20, 110, 15),
rnorm(20, 105, 15))
df_strategy <- data.frame(strategy, sales)
cat("=== 3 策略销售对比(ANOVA)===\n")
model <- aov(sales ~ strategy, data = df_strategy)
summary(model)
cat("\n事后检验:\n")
print(TukeyHSD(model))
# 7. 性别与购买行为(卡方)
gender <- sample(c("男", "女"), 200, replace = TRUE)
purchase <- sample(c("买", "不买"), 200, replace = TRUE,
prob = c(0.3, 0.7))
tab <- table(gender, purchase)
cat("\n=== 性别 vs 购买 卡方检验 ===\n")
print(tab)
cat("\n")
chisq_result <- chisq.test(tab)
print(chisq_result)
# 8. 综合报告
cat("\n=== 决策总结 ===\n")
cat("1. 转化时间:A 组比 B 组慢 ", round(cohens_d, 2), "个标准差",
ifelse(t_result$p.value < 0.05, "(显著)", "(不显著)"), "\n", sep = "")
cat("2. 转化率:A vs B 差异",
ifelse(prop_result$p.value < 0.05, "显著", "不显著"), "\n")
cat("3. 3 策略:",
ifelse(summary(model)[[1]]$`Pr(>F)`[1] < 0.05, "显著不同", "无差异"), "\n")
预期输出(节选):
TEXT
📖 仅展示
=== A/B 测试:转化时间 ===
A 组均值: 14.87 秒
B 组均值: 12.94 秒
差异: 1.93 秒
Welch Two Sample t-test
t = 3.18, df = 96.3, p-value = 0.002
Cohen's d(效应量): 0.643
效应大小: 中
=== 决策总结 ===
1. 转化时间:A 组比 B 组慢 0.64 个标准差(显著)
2. 转化率:A vs B 差异不显著
3. 3 策略:显著不同
❓ 常见问题
Q 卡方检验要求?
A 每个单元格期望频数 ≥ 5
📖 小节
- 假设检验 5 步:H0/H1 → 统计量 → p 值 → 决策 → 报告
- t 检验:
t.test(x, y)双样本 /paired = TRUE配对 /mu =单样本 - 比例检验:
prop.test(c(s1, s2), c(n1, n2))用于 A/B 测试 - 卡方检验:
chisq.test(table)独立性 /chisq.test(observed)拟合优度 - ANOVA:
aov(y ~ group)多组均值比较,事后用TukeyHSD() - p 值 ≠ 差异大小——必须配合效应量(Cohen's d / η²)
- 5 大陷阱:p-hacking、样本量大 p 必小、p < 0.05 ≠ 有用、不拒绝 ≠ 接受、显著 ≠ 实际
- p < 0.05 是统计显著门槛;实际意义看效应量 + 业务背景
📝 作业
-
基础题:模拟 30 个学生成绩(均 80 标准差 10),单样本 t 检验是否显著偏离 75 分;再模拟另 30 个(均 78),做双样本 t 检验。记录 p 值。
-
基础题:模拟 A/B 测试(A 组 1000 人转化 50,B 组 1000 人转化 80),用
prop.test检验差异是否显著。计算 Cohen's d 效应量。 -
基础题:构造 3x3 列联表(3 个广告渠道 × 是否点击),用
chisq.test检验渠道与点击是否独立。查看result$expected,所有期望频数 ≥ 5 吗? -
进阶题:模拟 3 种教学方法(每组 20 学生)的成绩,用
aov做 ANOVA,再TukeyHSD看哪两组差异最大。 -
挑战题:完整 A/B 测试——模拟 2 页面(各 1000 用户)的转化时间 + 转化率,用 t.test + prop.test + Cohen's d 综合评估,写出 1 段决策报告(p 值 + 效应量 + 业务建议)。截图保存。