第36课:学习曲线与模型诊断
学习目标
通过本课学习,你将能够:
- 理解学习曲线:描述学习曲线是如何随训练数据量变化来反映模型性能的。
- 诊断模型问题:通过解读训练分数和验证分数的变化曲线,判断模型是存在过拟合、欠拟合还是处于良好状态。
- 绘制与实践:使用
scikit-learn工具绘制和分析模型的学习曲线。 - 应用诊断方法:将学习曲线与前一课的偏差-方差理论相结合,为模型优化提供明确方向。
核心概念
想象一下,你正在教一个孩子学习骑自行车。如果只练习一次,他可能摔得很惨(欠拟合,学习不足)。如果让他反复在同一个小院子里练习,他可能变得非常熟练,但换个地方就可能不适应(过拟合,过于依赖特定环境)。一个理想的训练过程是,随着练习次数(数据量)和场地(数据多样性)的增加,他在任何路上都能骑得又稳又好(良好泛化)。
学习曲线就是这个过程的可视化图表。它通常绘制两条线:
- 训练分数曲线:随着训练数据量的增加,模型在训练集上的表现(如误差)如何变化。
- 验证分数曲线:随着训练数据量的增加,模型在验证集(或测试集)上的表现如何变化。
通过观察这两条曲线的形态和间距,我们可以直接“诊断”模型的健康状况:
- 欠拟合(高偏差):训练分数和验证分数都很差,且两者数值接近。曲线在底部趋于平稳,但分数仍然很低。这说明模型太简单,没有从数据中学到足够的规律。
- 过拟合(高方差):训练分数很好(误差低),但验证分数明显更差(误差高),两者之间有较大的间距。这说明模型对训练数据“死记硬背”,导致在新数据上表现不佳。
- 理想情况:训练分数和验证分数都收敛到一个较好的水平,且两者之间的间距很小。这说明模型具有很好的泛化能力。
结合上一课的偏差-方差权衡,学习曲线提供了直观的证据:欠拟合是偏差主导,需要增加模型复杂度;过拟合是方差主导,需要减少模型复杂度或增加数据。
代码示例
我们将使用 scikit-learn 的 learning_curve 工具来演示。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import learning_curve
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import make_pipeline
# 1. 创建一个带有一些噪声的简单二次数据集
np.random.seed(42)
X = np.sort(5 * np.random.rand(100, 1), axis=0)
y = np.sin(X).ravel() + np.random.normal(0, 0.1, 100) # sin(X) + 噪声
# 2. 定义一个函数来绘制学习曲线
def plot_learning_curve(estimator, title, X, y, cv=5):
"""
绘制给定模型的学习曲线。
estimator: 模型对象
title: 图表标题
X, y: 数据集
cv: 交叉验证折数
"""
train_sizes, train_scores, val_scores = learning_curve(
estimator, X, y, cv=cv, scoring='neg_mean_squared_error',
train_sizes=np.linspace(0.1, 1.0, 10), n_jobs=-1
)
# 计算训练和验证分数的均值和标准差(注意:分数是负的MSE,我们取反并开方得到RMSE)
train_scores_mean = np.sqrt(-train_scores.mean(axis=1))
train_scores_std = np.sqrt(-train_scores.std(axis=1))
val_scores_mean = np.sqrt(-val_scores.mean(axis=1))
val_scores_std = np.sqrt(-val_scores.std(axis=1))
plt.figure(figsize=(10, 6))
plt.title(title)
plt.xlabel("训练样本数")
plt.ylabel("RMSE (均方根误差)")
plt.grid()
# 绘制填充区域表示标准差
plt.fill_between(train_sizes, train_scores_mean - train_scores_std,
train_scores_mean + train_scores_std, alpha=0.1, color="r")
plt.fill_between(train_sizes, val_scores_mean - val_scores_std,
val_scores_mean + val_scores_std, alpha=0.1, color="g")
# 绘制平均分数曲线
plt.plot(train_sizes, train_scores_mean, 'o-', color="r", label="训练分数")
plt.plot(train_sizes, val_scores_mean, 'o-', color="g", label="验证分数")
plt.legend(loc="best")
plt.show()
# 3. 诊断:一个欠拟合的模型(线性回归,模型过于简单)
plot_learning_curve(LinearRegression(), "线性回归 (欠拟合)", X, y)
# 4. 诊断:一个过拟合的模型(高阶多项式回归)
degree = 15 # 多项式阶数设得非常高
poly_model = make_pipeline(PolynomialFeatures(degree, include_bias=False), LinearRegression())
plot_learning_curve(poly_model, f"多项式回归 (degree={degree}, 过拟合)", X, y)
# 5. 一个相对良好的模型(中等复杂度的多项式回归)
degree_good = 4 # 根据数据生成函数(sin)选一个合理的阶数
good_model = make_pipeline(PolynomialFeatures(degree_good, include_bias=False), LinearRegression())
plot_learning_curve(good_model, f"多项式回归 (degree={degree_good}, 良好拟合)", X, y)
代码解读:
- 我们创建了一个符合
y = sin(X) + 噪声分布的数据集。 plot_learning_curve函数封装了learning_curve的调用和绘图逻辑。注意,它返回的是负均方误差,我们为了方便解读,转换成了正的均方根误差(RMSE)。- 我们分别绘制了三种模型的学习曲线:
- 欠拟合:简单的线性模型无法捕捉数据的非线性规律,两条线都处于较高的误差水平。
- 过拟合:过于复杂的15阶多项式模型完美拟合了训练数据(训练误差很低),但对新数据(验证误差)预测很差,曲线间距很大。
- 良好拟合:4阶多项式模型很好地平衡了复杂度和泛化能力,两条线收敛到一个较低的误差值且间距很小。
实践练习
练习1:改变数据复杂度
将数据集生成函数从 np.sin(X) 改为 np.cos(X),并重新绘制线性回归的学习曲线。观察曲线形态是否发生变化?这说明了什么?
练习2:探索真实数据集
加载 scikit-learn 内置的波士顿房价数据集(from sklearn.datasets import load_boston)。使用线性回归模型绘制其学习曲线。你认为这个模型是欠拟合、过拟合还是相对良好?为什么?
练习3:寻找最佳复杂度
基于练习2的波士顿房价数据,尝试使用岭回归 (Ridge) 并手动调整其正则化参数 alpha(例如,测试 alpha=0.1, alpha=1, alpha=10)。为每个参数值绘制学习曲线,并讨论哪个 alpha 值产生的模型在泛化能力上可能最优。
常见错误
- 只看训练分数:认为训练分数低(误差小)模型就好。过拟合的模型训练分数极低,但实际使用时灾难性。
- 忽略曲线相对位置:过于关注分数的绝对值,而忽略训练曲线和验证曲线之间的间距。间距是衡量过拟合程度的关键指标。
- 数据量太小:学习曲线在训练样本很少时波动会很大(方差大)。需要足够大的数据量才能得出可靠结论。如果数据量确实很小,应考虑使用交叉验证来稳定估计。
- 混淆“验证分数”:绘制学习曲线时,验证分数通常来自交叉验证,而不是一个独立的测试集。在项目最终评估前,不要动用真正的测试集。
- 期望曲线完美收敛:在现实世界中,由于数据噪声和模型局限性,两条线可能不会完全重合,只要在达到一定数据量后间距稳定且数值可接受即可。
小结
- 学习曲线是通过绘制训练集大小与模型在训练集、验证集上的性能关系,来诊断模型泛化能力的强大工具。
- 关键解读:
- 欠拟合:训练/验证误差双高且接近。
- 过拟合:训练误差低,验证误差高,两者间距大。
- 良好拟合:两者误差均较低,且间距小。
- 它是偏差-方差权衡理论的直观体现:欠拟合(高偏差)可通过增加模型复杂度改善;过拟合(高方差)可通过增加数据、减少模型复杂度或增强正则化来改善。
- 在项目中,当模型表现不佳时,养成绘制学习曲线进行诊断的习惯,能为你指明下一步优化的具体方向,避免盲目调参。
练习编辑器
rust
Loading...