案例概述

使用广告投放数据(TV、Radio、Newspaper)预测销量(Sales)的多元线性回归实战案例。


1. 数据预处理

1.1 数据加载

dataset = pd.read_csv("../data/advertising.csv")

1.2 数据清洗

  • 缺失值处理: dataset.dropna(inplace=True) - 删除包含缺失值的行
  • 列删除: dataset.drop(columns=dataset.columns[0], axis=1, inplace=True) - 删除第一列(索引列)

1.3 数据探索

  • dataset.info() - 查看数据集信息(类型、非空数量等)
  • dataset.head() - 查看前5行数据

2. 数据集划分

2.1 特征与目标分离

X = dataset.drop(columns='Sales', axis=1)  # 特征: TV, Radio, Newspaper
y = dataset['Sales']                        # 目标: Sales

2.2 训练集与测试集划分

X_train, X_test, y_train, y_test = train_test_split(
    X, y, 
    test_size=0.3,      # 测试集占30%
    random_state=42     # 随机种子,保证可复现
)

知识点:

  • test_size: 测试集比例,常用值 0.2-0.3
  • random_state: 固定随机种子,确保每次划分结果一致

3. 特征工程 - 标准化

3.1 为什么需要标准化?

  • 不同特征的量纲(scale)不同,会影响梯度下降的收敛速度
  • 特别是使用SGD时,标准化能显著提升训练效率

3.2 StandardScaler 标准化

scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)  # 训练集: fit + transform
X_test = scaler.transform(X_test)        # 测试集: 只transform

关键原则:

  • ✅ 训练集: fit_transform() - 计算均值/方差并转换
  • ✅ 测试集: transform() - 使用训练集的均值/方差转换
  • ❌ 禁止: 测试集不能单独 fit_transform(),会导致数据泄露

数学原理:

x_scaled = (x - μ) / σ
  • μ: 均值
  • σ: 标准差
  • 结果: 均值为0,标准差为1

4. 模型训练 - 两种方法对比

4.1 正规方程法 (Normal Equation)

model_lr = LinearRegression()
model_lr.fit(X_train, y_train)

特点:

  • ✅ 直接求解析解,无需迭代
  • ✅ 不需要调参(无学习率等超参数)
  • ❌ 特征数量过多时(n > 10000),计算成本高
  • 时间复杂度: O(n³) - 需要矩阵求逆

数学公式:

θ = (X^T X)^(-1) X^T y

4.2 随机梯度下降法 (SGD)

model_sgd = SGDRegressor()
model_sgd.fit(X_train, y_train)

直觉理解(闭眼找山谷):

  • 想象在山上闭眼找最低点
  • 每一步:感受脚下坡度(梯度),朝下坡方向迈一小步(学习率 α)
  • 重复迭代,直到走到谷底(损失最小)
  • “随机”:每次只用一个随机样本估算方向,速度快但路径抖动
θ_new = θ_old - α · 梯度

对比正规方程:正规方程是直接算出答案;SGD 是一步步走到答案。

特点:

  • ✅ 适合大数据集(百万级样本)
  • ✅ 支持在线学习(增量学习)
  • ❌ 需要调参(学习率、迭代次数等)
  • ❌ 对特征缩放敏感(必须标准化)
  • 时间复杂度: O(m·k) - m是样本数,k是迭代次数

优化过程:

θ_new = θ_old - α · ∇J(θ)
  • α: 学习率
  • ∇J(θ): 损失函数梯度

5. 模型参数解读

5.1 系数 (Coefficients)

model_lr.coef_      # 返回 [θ1, θ2, θ3] - 对应TV、Radio、Newspaper的权重

含义: 每个特征对目标变量的影响程度

  • 正值: 正相关(该特征增加,销量增加)
  • 负值: 负相关
  • 绝对值大: 影响大

5.2 截距 (Intercept)

model_lr.intercept_  # 返回 θ0 - 基础销量

含义: 所有特征为0时的预测值

完整预测公式:

Sales = θ0 + θ1·TV + θ2·Radio + θ3·Newspaper

6. 模型评估

6.1 均方误差 (MSE - Mean Squared Error)

mse = mean_squared_error(y_test, y_pred)

含义: 预测值与真实值差的平方的平均值

MSE = (1/m) Σ(y_pred - y_true)²

特点:

  • 值越小越好,最小值为0(完美预测)
  • 对异常值敏感(因为平方项)
  • 单位是目标变量的平方

6.2 决定系数 (R² Score)

r2 = model_lr.score(X_test, y_test)

含义: 模型能解释的方差占比

R² = 1 - (SS_res / SS_tot)
  • SS_res: 残差平方和
  • SS_tot: 总平方和

直觉理解:

  • 基准线:不用模型,直接用销量均值预测 → R²=0
  • 模型越好,比"猜均值"提升越多 → R² 越接近 1
  • 例:R²=0.9 表示模型解释了 90% 的销量波动,剩余 10% 是噪声

取值范围:

含义
1.0完美预测
0.0等同于预测均值,模型没用
< 0比猜均值还差,模型有问题
  • 一般 R² > 0.7 算较好,> 0.9 算优秀

7. 完整工作流程总结

1. 数据加载 → 2. 数据清洗 → 3. 划分数据集 → 4. 特征标准化 
   ↓
5. 模型训练(LR/SGD) → 6. 模型预测 → 7. 模型评估(MSE/R²)

8. 两种方法选择建议

场景推荐方法原因
小数据集(< 10000样本)LinearRegression计算快,无需调参
大数据集(> 100000样本)SGDRegressor内存效率高
需要在线学习SGDRegressor支持增量训练
追求极致精度LinearRegression解析解更精确

9. 常见问题

Q1: 为什么SGD结果和正规方程不完全一致?

A: SGD是迭代优化,可能未完全收敛。可以通过增加 max_iter 或调整 learning_rate 改善。

Q2: 测试集要不要标准化?

A: 必须标准化,但只能用 scaler.transform(),不能重新 fit

Q3: 如何判断模型好坏?

A:

  • MSE: 越小越好,但要结合业务含义(如销量预测,MSE=100表示平均误差±10)
  • R²: 一般 >0.7 算较好, >0.9 算优秀

import pandas as pd

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler    # 标准化
from sklearn.linear_model import LinearRegression, SGDRegressor # 线性回归模型:正规方程法和SGD
from sklearn.metrics import mean_squared_error  # 均方误差损失函数

# 1. 读取数据集
dataset = pd.read_csv("../data/advertising.csv")

dataset.dropna(inplace=True)
dataset.drop(columns=dataset.columns[0], axis=1, inplace=True)

dataset.info()
print(dataset.head())

# 2. 划分数据集
X = dataset.drop(columns='Sales', axis=1)
y = dataset['Sales']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)

# 3. 特征工程:标准化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

# 4. 创建模型并训练
# 4.1 正规方程法
model_lr = LinearRegression()
model_lr.fit(X_train, y_train)

print("LR Coefficients: ", model_lr.coef_)
print("LR Intercept: ", model_lr.intercept_)

# 4.2 SGD
model_sgd = SGDRegressor()
model_sgd.fit(X_train, y_train)

print("SGD Coefficients: ", model_sgd.coef_)
print("SGD Intercept: ", model_sgd.intercept_)

# 5. 预测
y_pred1 = model_lr.predict(X_test)
y_pred2 = model_sgd.predict(X_test)

# 6. 使用均方误差评价模型
print("LR Mean Squared Error: ", mean_squared_error(y_test, y_pred1))
print("SGD Mean Squared Error: ", mean_squared_error(y_test, y_pred2))

print(model_lr.score(X_test, y_test))
print(model_sgd.score(X_test, y_test))

更多推荐