机器学习-线性回归-广告销量预测案例
·
案例概述
使用广告投放数据(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.3random_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% 是噪声
取值范围:
| R² | 含义 |
|---|---|
| 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))
更多推荐


所有评论(0)