代码演示之过拟合
1 课程概览
本课通过代码演示过拟合的实现。通过新增9列特征(X²到X⁹)增加模型复杂度,使模型过度拟合训练数据,导致测试集表现不好。对比欠拟合、正好拟合、过拟合三种情况的效果,引出解决过拟合的方法(L1/L2正则化)。
2 核心概念与定义
- 过拟合:模型过于复杂,训练集好但测试集不好。
- 增加特征列:新增X², X³, ..., X⁹等特征。
- hstack:NumPy中水平拼接数组的函数。
- 模型复杂度:特征越多,模型越复杂。
3 算法与模型详解
3.1 过拟合的实现方法
方法:新增多列特征(X²到X⁹),增加模型复杂度
原始特征:X (1列)
新增特征:
| 特征 | 说明 |
|---|---|
| X² | X的平方 |
| X³ | X的立方 |
| X⁴ | X的四次方 |
| ... | ... |
| X⁹ | X的九次方 |
总特征数:10列(X + X²~X⁹)
3.2 过拟合的表现
训练集:误差很小(模型过度拟合) 测试集:误差很大(泛化能力差)
曲线特征:拐弯过多,过度拟合每个数据点
3.3 三种拟合对比
| 类型 | 特征数 | 训练集 | 测试集 | 曲线 |
|---|---|---|---|---|
| 欠拟合 | 1列 | 不好 | 不好 | 直线 |
| 正好拟合 | 3列 | 好 | 好 | 平滑曲线 |
| 过拟合 | 10列 | 很好 | 不好 | 拐弯过多 |
3.4 解决过拟合的方法
方法1:减少特征数量
- 问题:可能删除重要特征(像人体微量元素)
方法2:L1正则化
- 使部分权重变为0
- 相当于特征选择
方法3:L2正则化
- 使权重接近0但不为0
- 削弱不重要特征的影响
3.5 hstack函数
作用:水平拼接多个数组
示例:
X = np.array([1, 2, 3])
X2 = X ** 2 # [1, 4, 9]
X3 = X ** 3 # [1, 8, 27]
# 水平拼接
X_combined = np.hstack([X, X2, X3])
4 数学原理与推导
4.1 过拟合模型
$$Y = W_0 + W_1X + W_2X^2 + W_3X^3 + ... + W_9X^9$$
4.2 过拟合表现
$$\text{训练误差} \downarrow\downarrow, \quad \text{测试误差} \uparrow$$
4.3 正则化
L1正则化: $$L = L_{original} + \lambda \sum |W_i|$$
L2正则化: $$L = L_{original} + \lambda \sum W_i^2$$
5 代码示例
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
# 1. 准备数据
np.random.seed(42)
X = np.sort(np.random.rand(30, 1) * 10, axis=0)
Y = np.sin(X).ravel() + np.random.randn(30) * 0.1
# 2. 模拟过拟合(新增9列特征)
def demo_overfitting():
"""演示过拟合"""
# 原始特征
X_base = X.ravel()
# 新增特征列 X²~X⁹
features = [X_base]
for i in range(2, 10):
features.append(X_base ** i)
# 水平拼接
X_over = np.vstack(features).T # 30行9列
print(f"处理后的特征形状: {X_over.shape}")
print(f"特征数: {X_over.shape[1]}")
# 训练模型
model = LinearRegression()
model.fit(X_over, Y)
# 预测
y_pred = model.predict(X_over)
# 评估
mse = mean_squared_error(Y, y_pred)
print(f"过拟合 MSE: {mse}")
return X_over, y_pred
# 运行
X_over, y_pred_over = demo_overfitting()
# 3. 三种拟合对比绘图
plt.figure(figsize=(15, 5))
# 欠拟合
plt.subplot(1, 3, 1)
lr1 = LinearRegression()
lr1.fit(X, Y)
plt.scatter(X, Y, color='blue', s=10)
plt.plot(X, lr1.predict(X), color='red')
plt.title('欠拟合(1次)')
# 正好拟合
plt.subplot(1, 3, 2)
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(degree=3)
X_poly = poly.fit_transform(X)
lr2 = LinearRegression()
lr2.fit(X_poly, Y)
plt.scatter(X, Y, color='blue', s=10)
plt.plot(X, lr2.predict(X_poly), color='green')
plt.title('正好拟合(3次)')
# 过拟合
plt.subplot(1, 3, 3)
plt.scatter(X, Y, color='blue', s=10)
plt.plot(X, y_pred_over, color='purple')
plt.title('过拟合(9次)')
plt.tight_layout()
plt.show()
6 重难点与易错提醒
- ❗重点:过拟合是模型太复杂,训练集好但测试集不好。
- ❗重点:增加特征列会增加模型复杂度。
- ❗重点:hstack用于水平拼接数组。
- ❗重点:过拟合解决方法:L1/L2正则化。
- ⚠️易错:特征数设置过多导致过拟合。
- ⚠️易错:简单删除特征可能丢失重要信息。
- 💡深入理解:正则化是解决过拟合的更好方法。
7 课堂问答精选
Q: 如何模拟过拟合?
A: 通过新增多列特征(如X²到X⁹)增加模型复杂度。使用hstack将多个特征列拼接在一起,使模型从1个特征变为10个特征,过度拟合训练数据。
Q: 为什么不能简单删除特征解决过拟合?
A: 简单删除特征可能丢失重要信息。有些特征虽然占比小但不可或缺(像人体微量元素)。更好的方法是使用L1/L2正则化,L1可以使不重要的特征权重变为0,L2可以使权重接近0但不为0。
8 本课小结
- 过拟合:模型太复杂,训练集好但测试集不好。
- 模拟方法:新增X²~X⁹等特征列。
- hstack:水平拼接数组。
- 三种拟合对比:欠拟合(直线)、正好拟合(平滑曲线)、过拟合(拐弯过多)。
- 解决方法:L1/L2正则化。
9 延伸思考与实践
- 实践:用代码演示三种拟合的对比。
- 预习:L1和L2正则化。
- 思考:如何判断模型是否过拟合?