代码演示之欠拟合
1 课程概览
本课讲解欠拟合和过拟合的概念、原因和解决方案。欠拟合是模型过于简单,训练集和测试集都不好;过拟合是模型过于复杂,训练集好但测试集不好;正好拟合是两者都好。通过误差曲线图分析模型复杂度与误差的关系,介绍L1和L2正则化用于解决过拟合。
2 核心概念与定义
- 欠拟合:模型过于简单,训练集和测试集表现都不好。
- 过拟合:模型过于复杂,训练集好但测试集不好。
- 正好拟合:训练集和测试集都好。
- 模型复杂度:特征数量越多,模型越复杂。
- L1正则化:解决过拟合的方法之一。
- L2正则化:解决过拟合的方法之一。
3 算法与模型详解
3.1 三种拟合情况对比
| 类型 | 训练集 | 测试集 | 原因 |
|---|---|---|---|
| 欠拟合 | 不好 | 不好 | 模型过于简单 |
| 正好拟合 | 好 | 好 | 模型复杂度适中 |
| 过拟合 | 好 | 不好 | 模型过于复杂 |
3.2 误差曲线分析
横轴:模型复杂度 纵轴:误差
曲线分析:
欠拟合区域(左侧):
- 训练误差大
- 测试误差大
- 模型太简单
正好拟合区域(中间):
- 训练误差小
- 测试误差达到最优
- 模型复杂度适中
过拟合区域(右侧):
- 训练误差继续减小
- 测试误差反而增大
- 模型太复杂
3.3 欠拟合原因与解决
原因:模型过于简单
解决方案:增加模型复杂度
方法:
- 增加特征
- 增加多项式特征
示例:
- 一元:根据学历预测工资
- 二元:根据学历+专业预测工资
- 三元:根据学历+专业+考试成绩预测工资
3.4 过拟合原因与解决
原因:模型过于复杂
解决方案:
- 减少特征数量
- L1正则化
- L2正则化
说明:
- L1和L2正则化都是解决过拟合
- 不能简单删除特征(可能像人体微量元素,占比小但不可或缺)
3.5 正则化作用
| 正则化 | 作用 |
|---|---|
| L1 | 解决过拟合,可使权重变为0(特征选择) |
| L2 | 解决过拟合,使权重接近0但不为0 |
4 数学原理与推导
4.1 欠拟合
$$\text{训练误差} \uparrow, \quad \text{测试误差} \uparrow$$
4.2 正好拟合
$$\text{训练误差} \downarrow, \quad \text{测试误差} \downarrow$$
4.3 过拟合
$$\text{训练误差} \downarrow\downarrow, \quad \text{测试误差} \uparrow$$
4.4 L1正则化
$$L = L_{original} + \lambda \sum |W_i|$$
4.5 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.preprocessing import PolynomialFeatures
from sklearn.metrics import mean_squared_error
# 生成数据
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
# 1. 欠拟合(一次线性回归)
lr_under = LinearRegression()
lr_under.fit(X, Y)
y_pred_under = lr_under.predict(X)
# 2. 正好拟合(三次多项式)
poly_features = PolynomialFeatures(degree=3)
X_poly = poly_features.fit_transform(X)
lr_good = LinearRegression()
lr_good.fit(X_poly, Y)
y_pred_good = lr_good.predict(X_poly)
# 3. 过拟合(20次多项式)
poly_over = PolynomialFeatures(degree=20)
X_poly_over = poly_over.fit_transform(X)
lr_over = LinearRegression()
lr_over.fit(X_poly_over, Y)
y_pred_over = lr_over.predict(X_poly_over)
# 绘图
plt.figure(figsize=(15, 5))
plt.subplot(1, 3, 1)
plt.scatter(X, Y, color='blue', label='数据点')
plt.plot(X, y_pred_under, color='red', label='欠拟合')
plt.title('欠拟合(一次)')
plt.legend()
plt.subplot(1, 3, 2)
plt.scatter(X, Y, color='blue', label='数据点')
plt.plot(X, y_pred_good, color='green', label='正好拟合')
plt.title('正好拟合(三次)')
plt.legend()
plt.subplot(1, 3, 3)
plt.scatter(X, Y, color='blue', label='数据点')
plt.plot(X, y_pred_over, color='purple', label='过拟合')
plt.title('过拟合(20次)')
plt.legend()
plt.tight_layout()
plt.show()
# 误差对比
print("欠拟合 MSE:", mean_squared_error(Y, y_pred_under))
print("正好拟合 MSE:", mean_squared_error(Y, y_pred_good))
print("过拟合 MSE:", mean_squared_error(Y, y_pred_over))
6 重难点与易错提醒
- ❗重点:欠拟合是模型太简单,训练集和测试集都不好。
- ❗重点:过拟合是模型太复杂,训练集好但测试集不好。
- ❗重点:欠拟合解决:增加模型复杂度(增加特征)。
- ❗重点:过拟合解决:L1/L2正则化。
- ⚠️易错:混淆欠拟合和过拟合的解决方法。
- ⚠️易错:认为过拟合可以通过简单删除特征解决。
- 💡深入理解:模型复杂度与误差的关系是U型曲线。
7 课堂问答精选
Q: 欠拟合和过拟合有什么区别?
A:
- 欠拟合:模型过于简单,训练集和测试集表现都不好。
- 过拟合:模型过于复杂,训练集好但测试集不好。
- 正好拟合:训练集和测试集都好。
Q: 如何解决欠拟合和过拟合?
A:
- 欠拟合:增加模型复杂度(增加特征、增加多项式特征)。
- 过拟合:L1正则化、L2正则化、减少特征数量。 注意:不能简单删除特征,因为有些特征虽然占比小但重要(像人体微量元素)。
8 本课小结
- 欠拟合:模型太简单,训练集和测试集都不好。
- 过拟合:模型太复杂,训练集好但测试集不好。
- 正好拟合:两者都好。
- 欠拟合解决:增加模型复杂度。
- 过拟合解决:L1/L2正则化。
- 误差曲线:U型,先减后增。
9 延伸思考与实践
- 实践:用多项式特征演示欠拟合和过拟合。
- 预习:正好拟合代码演示。
- 思考:为什么不能简单删除特征解决过拟合?