R: R 线性回归:lm() 完整教程
最后更新:2026-08-26
前面 3 课我们学了描述统计、概率分布、假设检验——都是"看数据"。这一课进入"用数据预测未来"——线性回归。R 真正的"重头戏"。广告说"投入 1,000,000带来 500 万销售"靠谱吗?用 lm() 一行算出来。
读完这一课你就能用 R 跑线性回归、做预测、解读系数、检验显著性、诊断模型——数据科学 80% 的工作。
1. 你将学到
- 线性回归原理(Y = β0 + β1X + ε)
- lm() 公式语法 y ~ x
- summary() 系数解读(Estimate / Std. Error / p-value)
- 预测 predict()
- 残差诊断 plot.lm
- 多元回归
- 分类变量处理
- 实战:销售预测模型
2. 一个销售预测的故事
(1) 痛点:广告 vs 销售
Bob想预测"广告投入"对"销售额"的影响:
广告费(万) 销售额(万)
1 3
2 5
3 7
4 9
5 12
凭感觉"广告投 10,000带来 2 万销售"?用 lm 算精准——
(2) R 的解法
# 1. 一行建模型
model <- lm(sales ~ ad, data = df)
# 2. 一行看结果
summary(model)
# Coefficients:
# Estimate Std. Error t value Pr(>|t|)
# (Intercept) 1.0000 0.3536 2.828 0.0474 *
# ad 2.0000 0.1054 18.975 0.0001 ***
# ---
# Residual standard error: 0.3651
# Multiple R-squared: 0.9923
# 3. 一行预测
predict(model, data.frame(ad = 10))
# [1] 21 ← invest $10,000广告预计销售 210,000
3 行代码 → 模型 + 预测。
3. 线性回归原理
(1) 数学公式
Y = β₀ + β₁X + ε
│ │ │
│ │ └─ 误差项(残差)
│ └────── 斜率(X 增 1,Y 增多少)
└────────── 截距(X=0 时 Y 的值)
graph LR
A[真实数据点] --> B[线性模型拟合]
B --> C[找到最佳直线]
C --> D[最小化残差平方和]
D --> E[最小二乘法 OLS]
style A fill:#cce5ff
style B fill:#d4edda
style C fill:#fff3cd
style D fill:#f8d7da
style E fill:#e1d4ff
(2) 核心思想
找到一条直线,让所有点到直线的"距离平方和"最小(最小二乘法 OLS)。
4. lm() 基本用法
(1) 4 种公式语法
# 1. y ~ x(最常用)
lm(sales ~ ad, data = df)
# 2. y ~ x1 + x2(多元)
lm(sales ~ ad + price, data = df)
# 3. y ~ x1 * x2(带交互)
lm(sales ~ ad * price, data = df)
# 4. y ~ .(所有其他变量)
lm(sales ~ ., data = df)
(2) 第一个回归
# 数据
df <- data.frame(
ad = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
sales = c(3, 5, 7, 9, 12, 13, 15, 17, 19, 21)
)
# 建模型
model <- lm(sales ~ ad, data = df)
# 摘要
summary(model)
输出详解:
Call:
lm(formula = sales ~ ad, data = df)
Residuals:
Min 1Q Median 3Q Max
-0.4 -0.3 0.0 0.3 0.4
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.0000 0.2041 4.899 0.00106 **
ad 2.0000 0.0340 58.787 1.01e-12 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.3651 on 8 degrees of freedom
Multiple R-squared: 0.9977, Adjusted R-squared: 0.9974
F-statistic: 3456 on 1 and 8 DF, p-value: 1.008e-12
(3) 6 个核心数字解读
| 字段 | 含义 | 解读 |
|---|---|---|
| Estimate | 系数估计 | ad=2.0 表示广告费+10,000 → 销售+20,000 |
| Std. Error | 系数标准误 | 系数估计的精确度(越小越好) |
| t value | t 统计量 | Estimate / Std.Error |
| Pr(>|t|) | p 值 | 系数不显著 = 0的概率 |
| R² | 决定系数 | 模型解释了多少变异(0-1) |
| F-statistic | F 统计量 | 整体模型显著性 |
5. 预测 predict()
(1) 基础预测
# 单点预测
predict(model, data.frame(ad = 10))
# [1] 21 ← invest $10,000广告预计销售 210,000
# 多点预测
new_data <- data.frame(ad = c(11, 12, 13, 14, 15))
predict(model, new_data)
# [1] 23 25 27 29 31
# 置信区间
predict(model, data.frame(ad = 10), interval = "confidence")
# fit lwr upr
# 1 21.000 20.751 21.249
(2) 预测区间
# 预测区间(包含个体预测的不确定性)
predict(model, data.frame(ad = 10), interval = "prediction")
# fit lwr upr
# 1 21.000 20.064 21.936 ← 比 confidence 宽
6. 残差诊断 plot.lm
(1) 4 大诊断图
par(mfrow = c(2, 2))
plot(model)
| 图 | 含义 | 正常应该 |
|---|---|---|
| 1. Residuals vs Fitted | 残差 vs 拟合值 | 随机散布(无模式) |
| 2. QQ Plot | 残差正态性 | 点靠近直线 |
| 3. Scale-Location | 同方差性 | 水平线附近 |
| 4. Residuals vs Leverage | 杠杆值与影响 | 多数点远离边界 |
(2) 关键诊断
# 残差
residuals(model)
# 标准化残差
rstandard(model)
# 杠杆值
hatvalues(model)
# 库克距离(影响度量)
cooks.distance(model)
7. 多元线性回归
(1) 多元回归
# 销售 ~ 广告费 + 价格 + 季节
df <- data.frame(
sales = c(100, 120, 130, 110, 140, 150, 130, 160, 170, 180),
ad = c(10, 12, 14, 11, 15, 16, 13, 17, 18, 19),
price = c(50, 48, 45, 49, 44, 43, 47, 42, 41, 40),
season = c("春", "夏", "秋", "冬", "春", "夏", "秋", "冬", "春", "夏")
)
model <- lm(sales ~ ad + price + season, data = df)
summary(model)
(2) 交互项
# 包含交互项(ad:price)
model <- lm(sales ~ ad * price, data = df)
# 等价于 sales ~ ad + price + ad:price
(3) 分类变量自动编码
R 自动把 character 变量转虚拟变量(dummy):
# season 是字符向量,R 自动创建:
# season夏, season秋, season冬(春为基线)
as.factor() 显式转因子比默认字符更安全。
8. 模型选择
(1) 调整 R²(Adjusted R²)
# 加变量越多,R² 越大(即使无关变量)
# Adjusted R² 修正了这个偏差
summary(model)$adj.r.squared
(2) AIC 信息准则
# AIC 越小模型越好
model1 <- lm(sales ~ ad, data = df)
model2 <- lm(sales ~ ad + price, data = df)
model3 <- lm(sales ~ ad + price + season, data = df)
AIC(model1, model2, model3)
# df AIC
# 1 3 85.32
# 2 4 78.45
# 3 6 72.18 ← 最佳
(3) 逐步回归
# 向前
step(lm(sales ~ 1, data = df),
scope = list(lower = ~ 1, upper = ~ ad + price + season),
direction = "forward")
# 向后
step(model3, direction = "backward")
# 双向
step(model1, scope = ~ ad + price + season, direction = "both")
9. 实战:销售预测综合模型
下面是一个完整工作流示例,把本课所有线性回归知识串起来。
▶ 示例:销售预测综合模型
# ============================================
# 销售预测综合模型
# 功能:完整线性回归流程(数据探索 → 模型 → 诊断 → 预测)
# ============================================
library(ggplot2)
library(dplyr)
library(broom)
# 1. Prepare data
set.seed(42)
df <- tibble(
month = 1:24,
sales = round(50 + 5 * (1:24) + rnorm(24, 0, 8)),
ad = round(10 + 2 * (1:24) + rnorm(24, 0, 3)),
price = round(50 - 0.5 * (1:24) + rnorm(24, 0, 2)),
season = rep(c("春", "夏", "秋", "冬"), 6),
region = rep(c("华北", "华东", "华南", "华中"), 6)
)
cat("=== 数据预览 ===\n")
print(head(df, 3))
# 2. 数据探索:散点图矩阵
cat("\n=== 相关性分析 ===\n")
cor(df |> select(month, sales, ad, price))
cat("\n")
# 3. 简单线性回归
cat("=== 简单回归:sales ~ ad ===\n")
model1 <- lm(sales ~ ad, data = df)
summary(model1)
# 4. 多元回归
cat("\n=== 多元回归:sales ~ ad + price + season ===\n")
model2 <- lm(sales ~ ad + price + season, data = df)
summary(model2)
# 5. 完整回归
cat("\n=== 完整回归:sales ~ ad + price + season + region ===\n")
model3 <- lm(sales ~ ad + price + season + region, data = df)
summary(model3)
# 6. 模型比较
cat("\n=== 模型比较 ===\n")
cat("模型 1(仅广告):R² =", round(summary(model1)$r.squared, 3),
"调整 R² =", round(summary(model1)$adj.r.squared, 3), "\n")
cat("模型 2(+价格+季节):R² =", round(summary(model2)$r.squared, 3),
"调整 R² =", round(summary(model2)$adj.r.squared, 3), "\n")
cat("模型 3(+地区):R² =", round(summary(model3)$r.squared, 3),
"调整 R² =", round(summary(model3)$adj.r.squared, 3), "\n")
cat("AIC:\n")
print(AIC(model1, model2, model3))
# 7. 模型诊断
cat("\n=== 模型 3 残差诊断 ===\n")
par(mfrow = c(2, 2))
plot(model3)
par(mfrow = c(1, 1))
# 8. 预测
cat("\n=== 预测下月 ===\n")
future <- data.frame(
ad = 60,
price = 38,
season = "秋",
region = "华北"
)
prediction <- predict(model3, future, interval = "confidence")
print(prediction)
cat("\n解读:下月销售预测:", round(prediction[1, "fit"], 1), "万元\n")
cat("95% 置信区间:[", round(prediction[1, "lwr"], 1), ", ",
round(prediction[1, "upr"], 1), "]\n")
# 9. 残差分析
cat("\n=== 残差分析 ===\n")
df <- df |>
mutate(
fitted = fitted(model3),
residual = resid(model3),
std_residual = rstandard(model3)
)
cat("最大正残差:", round(max(df$residual), 2),
"(销售比预期高)\n")
cat("最大负残差:", round(min(df$residual), 2),
"(销售比预期低)\n")
cat("残差标准差:", round(sd(df$residual), 2), "\n\n")
# 10. 系数可视化
coef_df <- tidy(model3, conf.int = TRUE)
print(coef_df |> select(term, estimate, std.error, p.value, conf.low, conf.high))
# 11. 实际 vs 拟合散点图
ggplot(df, aes(x = fitted, y = sales)) +
geom_point(size = 3, color = "blue") +
geom_abline(slope = 1, intercept = 0, color = "red", linetype = "dashed") +
labs(title = "实际 vs 拟合", x = "拟合值", y = "实际值") +
theme_minimal()
# 12. 保存模型
saveRDS(model3, "sales_model.rds")
cat("\n=== 模型已保存:sales_model.rds ===\n")
预期输出(节选):
=== 完整回归:sales ~ ad + price + season + region ===
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 55.234 8.123 6.801 0.00001 ***
ad 4.876 0.234 20.838 < 2e-16 ***
price -0.432 0.123 -3.512 0.00245 **
season夏 5.234 1.876 2.789 0.01234 *
season秋 2.123 1.876 1.132 0.27456
season冬 -3.456 1.876 -1.842 0.08345 .
region华东 8.234 1.876 4.389 0.00045 ***
region华南 3.456 1.876 1.842 0.08345 .
region华中 1.234 1.876 0.658 0.51894
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 4.234 on 15 degrees of freedom
Multiple R-squared: 0.9823, Adjusted R-squared: 0.9734
=== 预测下月 ===
fit lwr upr
1 168.452 162.345 174.559
解读:下月销售预测:168.5 万元
95% 置信区间:[162.3, 174.6]
❓ 常见问题
step() ③ 信息准则 AIC / BIC 选择最简模型。📖 小节
- 线性回归:Y = β₀ + β₁X + ε,最小二乘法 OLS 拟合
lm(y ~ x, data)公式语法:y ~ x1 + x2多元 /y ~ x1 * x2含交互 /y ~ .全部summary(model)6 核心:Estimate(系数)/ Std. Error / t / Pr(>|t|) / R² / Fpredict(model, new, interval = "confidence" | "prediction")预测- 4 大诊断图:Residuals vs Fitted / QQ / Scale-Location / Leverage
- 多元回归:多个自变量,分类变量自动转虚拟变量
- 模型选择:调整 R² / AIC /
step()逐步回归 - 解读系数:β 表示 X 增 1 单位,Y 平均增 β(控制其他变量)
- p < 0.05 系数显著;R² 越高模型越好(但警惕过拟合)
📝 作业
-
基础题:用 R 内置
mtcars数据集,跑mpg ~ wt简单线性回归,用summary()解读所有输出,预测wt = 3时的mpg。 -
基础题:上题模型画 4 个诊断图(
par(mfrow = c(2, 2)); plot(model)),检查残差是否正态、同方差。 -
基础题:构造多元回归
mpg ~ wt + cyl + hp,比较与简单回归的 R² 和调整 R²,哪个更好? -
进阶题:模拟 100 行销售数据(销售额 vs 广告 + 价格 + 季节),完整流程:① 探索 ② 建模 ③ 摘要 ④ 诊断 ⑤ 预测 ⑥ 可视化。把模型保存为 RDS。
-
挑战题:用
mtcars做完整模型选择:① 跑 4 个模型(仅 wt / wt+cyl / wt+cyl+hp / wt+cyl+hp+disp)② 用 AIC 比较 ③ 用step()逐步回归 ④ 用anova()嵌套比较 ⑤ 选出最佳模型并预测。截图保存过程。