learning_curve | 学习、理解以及使用学习曲线在评估型性能和诊断模型问题中的使用
- 什么是学习曲线
学习曲线是机器学习中用来评估模型性能和诊断模型问题的一种工具。它通过展示模型在不同大小的训练集上的性能来帮助我们理解模型的学习过程。
学习曲线通常包括两个部分:训练集上的性能(训练分数)和验证集或交叉验证集上的性能(验证分数)。
学习曲线通常与交叉验证一起使用,以获得更稳定的性能估计。
学习曲线
- 一般步骤
- 核心步骤
- 网格搜索确定模型的最优参数
- 交叉验证策略
- learning_curve⭐
- 过拟合(Overfitting)
- 欠拟合(Underfitting)
一般步骤
生成学习曲线并用它们来分析模型性能通常涉及以下步骤:
-
准备数据集:
- 将数据集分为特征(X)和目标变量(y)。
-
选择模型:
- 选择一个机器学习模型,比如逻辑回归、决策树、支持向量机等。
-
划分数据集:
- 将数据集划分为训练集和测试集,或者使用交叉验证来评估模型性能。
-
定义训练集大小:
- 确定一系列不同的训练集大小,这些大小将用于生成学习曲线。通常,这些大小是原始训练集大小的百分比,例如 10%, 25%, 50%, 75%, 100%。
-
使用学习曲线函数:
- 在 scikit-learn 中,可以使用
learning_curve
函数来生成学习曲线。这个函数将计算在不同大小的训练集上模型的训练分数和验证分数。
- 在 scikit-learn 中,可以使用
-
绘制学习曲线:
- 使用绘图库(如 matplotlib 或 seaborn)来绘制训练分数和验证分数随训练集大小变化的曲线。
-
分析学习曲线:
- 观察训练分数和验证分数的趋势,以及它们之间的差距,以判断模型是否存在高偏差或高方差的问题。
- 通过一组代码来学习
from sklearn.model_selection import ShuffleSplit
from sklearn.model_selection import learning_curve
def plot_learning_curve(estimator, X, y, ylim=None, cv=None,
n_jobs=1, train_sizes=np.linspace(.1, 1.0, 5)):
f, ax1 = plt.subplots(1,1, figsize=(10,6), sharey=True)
if ylim is not None:
plt.ylim(*ylim)
# First Estimator
train_sizes, train_scores, test_scores = learning_curve(estimator, X, y, cv=cv, n_jobs=n_jobs, train_sizes=train_sizes)
print('train_sizes:',train_sizes)
print('train_scores:',train_scores)
print('test_scores:',test_scores)
train_scores_mean = np.mean(train_scores, axis=1)
train_scores_std = np.std(train_scores, axis=1)
test_scores_mean = np.mean(test_scores, axis=1)
test_scores_std = np.std(test_scores, axis=1)
ax1.fill_between(train_sizes, train_scores_mean - train_scores_std,
train_scores_mean + train_scores_std, alpha=0.1,
color="#ff9124")
ax1.fill_between(train_sizes, test_scores_mean - test_scores_std,
test_scores_mean + test_scores_std, alpha=0.1, color="#2492ff")
ax1.plot(train_sizes, train_scores_mean, 'o-', color="#ff9124",label="Training score")
ax1.plot(train_sizes, test_scores_mean, 'o-', color="#2492ff",label="Cross-validation score")
ax1.set_title("Logistic Regression Learning Curve", fontsize=14)
ax1.set_xlabel('Training size (m)')
ax1.set_ylabel('Score')
ax1.grid(True)
ax1.legend(loc="best")
return plt
title = "Learning Curves (lr C:10, penalty: l2})"
estimator = LogisticRegression(penalty='l2', C=10.0)# 提供的最优参数,训练模型查看是否过拟合
cv = ShuffleSplit(n_splits=5, test_size=0.3, random_state=42)
plt = plot_learning_curve(estimator, X, y, (0.87, 1.01), cv=cv, n_jobs=4) # SMOTE后的X ,y
plt.title(title)
- 结果
train_sizes: [ 39804 129363 218922 308481 398041]
train_scores: [[0.93947844 0.94121194 0.94379962 0.942041 0.93684052]
[0.93869963 0.93858368 0.93944173 0.93900111 0.9366434 ]
[0.93802359 0.93839358 0.93840272 0.9386037 0.93774495]
[0.93783086 0.93864776 0.93838843 0.93831711 0.93760394]
[0.93773255 0.9383355 0.93800639 0.93803151 0.93787323]]
test_scores: [[0.93994923 0.93814373 0.9415613 0.94070544 0.93812028]
[0.93850131 0.93745787 0.93885303 0.93793269 0.93835476]
[0.93862441 0.93769235 0.9384251 0.93816717 0.93861269]
[0.93861269 0.93776855 0.93844269 0.93792097 0.93861855]
[0.93870648 0.93765131 0.93843683 0.93786821 0.93872993]]
核心步骤
网格搜索确定模型的最优参数
# 提供的最优参数,训练模型查看是否过拟合
# 模型调优采用网格搜索调优参数(grid search)-> 获取模型训练最佳参数
estimator = LogisticRegression(penalty='l2', C=10.0)
cv = ShuffleSplit(n_splits=5, test_size=0.3, random_state=42) # 是一种交叉验证策略
train_sizes, train_scores, test_scores = learning_curve(estimator, X, y, cv=cv, n_jobs=1, train_sizes=np.linspace(.1, 1.0, 5))
- 网格搜索
在确定下面模型的最优参数前是需要通过网格搜索来确定的
estimator = LogisticRegression(penalty='l2', C=10.0)
交叉验证策略
你可以使用 KFold、StratifiedKFold 或 ShuffleSplit 等交叉验证策略【后续有机会补充】
cv = ShuffleSplit(n_splits=5, test_size=0.3, random_state=42)
ShuffleSplit:这是一个交叉验证生成器,它将数据随机打乱,然后按照指定的比例划分为训练集和测试集(验证集)。这种策略也被称为随机划分验证策略。
n_splits=5:这个参数指定了数据应该被划分成训练集和测试集的次数。在这个例子中,数据将被随机划分5次,每次划分都会产生一个新的训练集和测试集。
test_size=0.3:这个参数指定了测试集(验证集)占总数据集的比例。在这里,0.3表示30%的数据将被用作测试集,剩下的70%将被用作训练集。
learning_curve⭐
train_sizes, train_scores, test_scores = learning_curve(estimator, X, y, cv=cv, n_jobs=1, train_sizes=np.linspace(.1, 1.0, 5))
'''
输出:(train_sizes :训练样本数
train_scores:训练集上准确率
test_scores:交叉验证集上的准确率)
'''
learning_curve 函数计算在不同大小的训练集上模型的训练分数和测试分数。
estimator 是之前定义的逻辑回归模型。
X 和 y 分别是特征矩阵和目标向量。
cv 是之前定义的交叉验证策略。
n_jobs=1 表示计算过程中不使用并行处理,即只使用一个核心。如果设置为-1,将使用所有可用的核心。
train_sizes=np.linspace(.1, 1.0, 5) 定义了5个不同的训练集大小,这些大小是原始训练集大小的10%、30%、50%、70%和100%。
这里有个疑问:learning_curve 方法中的train_sizes参数和ShuffleSplit中的n_splits有关系吗?
train_sizes 和 n_splits 都是用来控制模型训练和评估过程中数据的使用方式,但它们关注的方面不同。train_sizes关注的是训练集的大小,而 n_splits 关注的是交叉验证的折叠数或随机分割的次数。 在使用 learning_curve函数时,对于每个 train_sizes 中定义的训练集大小,n_splits指定的交叉验证策略都会被应用。这意味着,对于每个训练集大小,模型都会进行 n_splits 次训练和评估,以获得更稳定的性能估计。
- 执行过程
现在,让我们将这两个概念结合起来理解它们是如何在 learning_curve 函数中一起工作的:
对于 train_sizes 中定义的每个训练集大小,learning_curve 函数都会执行以下步骤:
- 随机选择原始训练集的相应比例作为当前的训练集(例如,第一次迭代中使用10%的数据)。
- 使用 cv 参数定义的交叉验证策略(例如,ShuffleSplit 或 KFold)进一步将这个
10%训练集
分割成多个训练集和验证集。 - 对于 n_splits=5,这意味着即使我们只使用了原始训练集的10%,在每次交叉验证迭代中,这10%的数据还会被进一步根据test_size分割,其中1-test_size部分用于训练,test_size部分用于验证,n_splits=5 表示这种随机分割将重复5次。每次分割都是独立的,这意味着每次都会随机选择test_size部分数据作为测试集,剩下的作为训练集。。
- 模型在这些训练集上训练,并在相应的验证集上评估,以计算性能指标(如准确率)。这个过程重复 n_splits 次,每次都随机选择数据的不同部分作为验证集。
你设置 train_sizes=np.linspace(0.1, 1.0, 5) 和 cv=ShuffleSplit(n_splits=5, test_size=0.3, random_state=42),那么对于每个训练集大小(例如10%),都会有5次随机分割的训练和测试过程,其中测试集占30%,训练集占70%。这样,对于原始训练集的10%,实际用于训练的数据将是7%(即10%的70%),而用于测试的数据将是3%(即10%的30%)。这个过程会重复进行,以生成学习曲线上每个点的性能数据。都会有5次随机分割的训练和测试过程,总共会有 5 * 5 = 25 次模型训练和评估。
可以看看这篇文章机器学习之学习曲线learning curve和过拟合、欠拟合去学习根据图像结果如何分析问题
- 过拟合 欠拟合
过拟合(Overfitting)和欠拟合(Underfitting)是机器学习中两个常见的概念,它们描述了模型在训练数据上的表现与新数据上的表现之间的关系。下面我将用通俗的语言来解释这两个概念:
过拟合(Overfitting)
想象一下,你是一位厨师,正在尝试根据食谱制作一道新菜。过拟合就像是你过于精确地按照食谱操作,以至于你的菜只适合这个特定的食谱,对于任何微小的变化(比如不同的食材品牌或者稍微不同的烹饪条件)都无法适应。在机器学习中,这意味着模型在训练数据上表现得非常好,几乎能够完美预测训练集中的所有结果,但它在新的、未见过的数据上表现很差,因为它学到了训练数据中的噪声和细节,而没有抓住数据背后的真实规律。
欠拟合(Underfitting)
还是以厨师为例,欠拟合就像是你只得到了一个非常粗略的食谱,比如“把东西混合在一起加热”。这个食谱太简单了,没有提供足够的指导,所以你无法做出一道像样的菜。在机器学习中,这意味着模型在训练数据上的表现就很差,无法捕捉到数据中的基本规律和结构。这通常是因为模型太简单,没有足够的能力来学习数据的特征。
简而言之:
- 过拟合:模型在训练数据上表现太好,以至于无法泛化到新数据。
- 欠拟合:模型在训练数据上表现太差,没有学到数据的基本规律。
一个好的模型应该在训练数据上表现良好,同时也能在新数据上表现良好,这种状态被称为“良好拟合”或“恰当拟合”。