R: R 线性回归:lm() 完整教程

最后更新:2026-08-26

前面 3 课我们学了描述统计、概率分布、假设检验——都是"看数据"。这一课进入"用数据预测未来"——线性回归。R 真正的"重头戏"。广告说"投入 1,000,000带来 500 万销售"靠谱吗?用 lm() 一行算出来。

读完这一课你就能用 R 跑线性回归、做预测、解读系数、检验显著性、诊断模型——数据科学 80% 的工作。

1. 你将学到



2. 一个销售预测的故事

(1) 痛点:广告 vs 销售

Bob想预测"广告投入"对"销售额"的影响:

TEXT 📖 仅展示
广告费(万)   销售额(万)
1            3
2            5
3            7
4            9
5            12

凭感觉"广告投 10,000带来 2 万销售"?用 lm 算精准——

(2) R 的解法

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) 数学公式

TEXT 📖 仅展示
Y = β₀ + β₁X + ε
   │   │    │
   │   │    └─ 误差项(残差)
   │   └────── 斜率(X 增 1,Y 增多少)
   └────────── 截距(X=0 时 Y 的值)
100%
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 种公式语法

R
# 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) 第一个回归

R
# 数据
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)

输出详解:

TEXT 📖 仅展示
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的概率
决定系数 模型解释了多少变异(0-1)
F-statistic F 统计量 整体模型显著性
💡 关键:系数 p < 0.05 说明系数"显著不等于 0"——这个变量对 Y 有显著影响



5. 预测 predict()

(1) 基础预测

R
# 单点预测
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) 预测区间

R
# 预测区间(包含个体预测的不确定性)
predict(model, data.frame(ad = 10), interval = "prediction")
#       fit    lwr    upr
# 1 21.000 20.064 21.936  ← 比 confidence 宽


6. 残差诊断 plot.lm

(1) 4 大诊断图

R
par(mfrow = c(2, 2))
plot(model)
含义 正常应该
1. Residuals vs Fitted 残差 vs 拟合值 随机散布(无模式)
2. QQ Plot 残差正态性 点靠近直线
3. Scale-Location 同方差性 水平线附近
4. Residuals vs Leverage 杠杆值与影响 多数点远离边界

(2) 关键诊断

R
# 残差
residuals(model)

# 标准化残差
rstandard(model)

# 杠杆值
hatvalues(model)

# 库克距离(影响度量)
cooks.distance(model)


7. 多元线性回归

(1) 多元回归

R
# 销售 ~ 广告费 + 价格 + 季节
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) 交互项

R
# 包含交互项(ad:price)
model <- lm(sales ~ ad * price, data = df)
# 等价于 sales ~ ad + price + ad:price

(3) 分类变量自动编码

R 自动把 character 变量转虚拟变量(dummy)

R
# season 是字符向量,R 自动创建:
# season夏, season秋, season冬(春为基线)
💡 提示as.factor() 显式转因子比默认字符更安全。



8. 模型选择

(1) 调整 R²(Adjusted R²)

R
# 加变量越多,R² 越大(即使无关变量)
# Adjusted R² 修正了这个偏差
summary(model)$adj.r.squared

(2) AIC 信息准则

R
# 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) 逐步回归

R
# 向前
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. 实战:销售预测综合模型

下面是一个完整工作流示例,把本课所有线性回归知识串起来。

▶ 示例:销售预测综合模型

R 📖 仅展示
# ============================================
# 销售预测综合模型
# 功能:完整线性回归流程(数据探索 → 模型 → 诊断 → 预测)
# ============================================

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")
逻辑代码 72 行(超过 40 行限制,仅展示)

预期输出(节选):

TEXT 📖 仅展示
=== 完整回归: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]

❓ 常见问题

Q 系数不显著怎么办?
A 4 种可能:① 样本不够 ② 变量真的无关 ③ 多重共线(与别的变量相关)④ 需要变量变换。
Q 多元回归怎么选变量?
A 3 种方法:① 业务理解(专家经验) ② 逐步回归 step() ③ 信息准则 AIC / BIC 选择最简模型。

📖 小节


📝 作业

  1. 基础题:用 R 内置 mtcars 数据集,跑 mpg ~ wt 简单线性回归,用 summary() 解读所有输出,预测 wt = 3 时的 mpg

  2. 基础题:上题模型画 4 个诊断图(par(mfrow = c(2, 2)); plot(model)),检查残差是否正态、同方差。

  3. 基础题:构造多元回归 mpg ~ wt + cyl + hp,比较与简单回归的 R² 和调整 R²,哪个更好?

  4. 进阶题:模拟 100 行销售数据(销售额 vs 广告 + 价格 + 季节),完整流程:① 探索 ② 建模 ③ 摘要 ④ 诊断 ⑤ 预测 ⑥ 可视化。把模型保存为 RDS。

  5. 挑战题:用 mtcars 做完整模型选择:① 跑 4 个模型(仅 wt / wt+cyl / wt+cyl+hp / wt+cyl+hp+disp)② 用 AIC 比较 ③ 用 step() 逐步回归 ④ 用 anova() 嵌套比较 ⑤ 选出最佳模型并预测。截图保存过程。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏