Python实践通过使用XGBoost中的尽早停止【Early Stopping】策略来避免过度拟合

        【翻译自 :  Avoid Overfitting By Early Stopping With XGBoost In Python】

        【说明:Jason Brownlee PhD大神的文章个人很喜欢,所以闲暇时间里会做一点翻译和学习实践的工作,这里是相应工作的实践记录,希望能帮到有需要的人!】

         过度拟合是复杂的非线性学习算法(例如梯度提升)的一个问题。

        在本文中,您将发现如何使用早期停止来限制Python中XGBoost的过拟合。阅读这篇文章后,您将知道:

关于尽早停止训练是减少训练数据过度拟合的一种方法。
如何在训练期间监视XGBoost模型的性能并绘制学习曲线。
如何使用早期停止以最佳时期提前停止XGBoost模型的训练。

尽早停止以避免过度拟合

      提早停止是一种训练复杂的机器学习模型以避免过度拟合的方法。它通过监视在单独的测试数据集上进行训练的模型的性能并在固定次数的训练迭代后测试数据集的性能未得到改善的情况下停止训练过程来工作。通过尝试自动选择拐点,在拐点处测试数据集的性能开始下降,而训练数据集的性能随着模型开始过拟合而继续提高,从而避免了过拟合。性能度量可以是为训练模型而优化的损失函数(例如对数损失),或者通常是该问题感兴趣的外部度量(例如分类精度)。

使用XGBoost观察训练效果

        XGBoost模型可以在训练过程中评估和报告模型测试集的性能。它通过在训练模型和指定详细输出时在对model.fit()的调用中同时指定测试数据集和评估指标来支持此功能。例如,在训练XGBoost模型时,我们可以报告独立测试集(eval_set)上的二进制分类错误率(“ error”),如下所示:

eval_set = [(X_test, y_test)]
model.fit(X_train, y_train, eval_metric="error", eval_set=eval_set, verbose=True)

XGBoost支持一套评估指标,不仅限于:

均方根误差为“ rmse”。
“ mae”表示平均绝对误差。
“ logloss”代表二进制对数损失,“ mlogloss”代表多类对数损失(交叉熵)。
“错误”表示分类错误。
ROC曲线下的面积为“ auc”。

       例如,我们可以演示如何在Pima Indians糖尿病发病数据集上跟踪XGBoost模型训练的性能。下载数据集文件并将其放置在当前工作目录中。

数据集文件
数据集详细信息
      下面提供了完整的示例:

# monitor training performance
from numpy import loadtxt
from xgboost import XGBClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# load data
dataset = loadtxt('pima-indians-diabetes.csv', delimiter=",")
# split data into X and y
X = dataset[:,0:8]
Y = dataset[:,8]
# split data into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.33, random_state=7)
# fit model no training data
model = XGBClassifier()
eval_set = [(X_test, y_test)]
model.fit(X_train, y_train, eval_metric="error", eval_set=eval_set, verbose=True)
# make predictions for test data
y_pred = model.predict(X_test)
predictions = [round(value) for value in y_pred]
# evaluate predictions
accuracy = accuracy_score(y_test, predictions)
print("Accuracy: %.2f%%" % (accuracy * 100.0))

       每个训练时期评估模型。在每次迭代中报告分类错误,最后在最后报告分类准确性。

       注意:由于算法或评估程序的随机性,或者数值精度的差异,您的结果可能会有所不同。 考虑运行该示例几次并比较平均结果。下面提供了输出,为简洁起见,将其截断。 我们可以看到,每次训练迭代时都会报告分类错误(在将每个提升树添加到模型之后)。

[89]	validation_0-error:0.204724
[90]	validation_0-error:0.208661
[91]	validation_0-error:0.208661
[92]	validation_0-error:0.208661
[93]	validation_0-error:0.208661
[94]	validation_0-error:0.208661
[95]	validation_0-error:0.212598
[96]	validation_0-error:0.204724
[97]	validation_0-error:0.212598
[98]	validation_0-error:0.216535
[99]	validation_0-error:0.220472
Accuracy: 77.95%

        回顾所有输出,我们可以看到测试集上的模型性能平稳,甚至在训练结束时变得更糟。

使用学习曲线评估XGBoost模型

       我们可以在评估数据集上检索模型的性能并将其绘制出来,以深入了解培训过程中学习的发展情况。在拟合XGBoost模型时,我们为eval_metric参数提供了X和y对数组。 除了测试集,我们还可以提供训练数据集。 这将提供有关模型在训练过程中在训练和测试集上的表现的报告。

       例如:

eval_set = [(X_train, y_train), (X_test, y_test)]
model.fit(X_train, y_train, eval_metric="error", eval_set=eval_set, verbose=True)

        此外,模型在每个评估集上的性能都可以通过调用model.evals_result()函数在训练后由模型存储和使用。 这将返回评估数据集和分数的字典,例如:

results = model.evals_result()
print(results)

        这将打印如下结果(为简洁起见,将其截断):

{
	'validation_0': {'error': [0.259843, 0.26378, 0.26378, ...]},
	'validation_1': {'error': [0.22179, 0.202335, 0.196498, ...]}
}

        “ validation_0”和“ validation_1”中的每一个都对应于在fit()调用中将数据集提供给eval_set参数的顺序。

       可以按以下方式访问特定结果数组,例如第一个数据集和错误度量的结果:

results['validation_0']['error']

       另外,我们可以为fit()函数的eval_metric参数提供一组度量标准,以指定更多评估度量标准以进行评估和收集。

      然后,我们可以使用这些收集的性能指标来创建折线图,并进一步了解模型在训练期间在训练和测试数据集上的行为方式。

      以下是完整的代码示例,显示了如何在折线图中可视化收集的结果。

# plot learning curve
from numpy import loadtxt
from xgboost import XGBClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from matplotlib import pyplot
# load data
dataset = loadtxt('pima-indians-diabetes.csv', delimiter=",")
# split data into X and y
X = dataset[:,0:8]
Y = dataset[:,8]
# split data into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.33, random_state=7)
# fit model no training data
model = XGBClassifier()
eval_set = [(X_train, y_train), (X_test, y_test)]
model.fit(X_train, y_train, eval_metric=["error", "logloss"], eval_set=eval_set, verbose=True)
# make predictions for test data
y_pred = model.predict(X_test)
predictions = [round(value) for value in y_pred]
# evaluate predictions
accuracy = accuracy_score(y_test, predictions)
print("Accuracy: %.2f%%" % (accuracy * 100.0))
# retrieve performance metrics
results = model.evals_result()
epochs = len(results['validation_0']['error'])
x_axis = range(0, epochs)
# plot log loss
fig, ax = pyplot.subplots()
ax.plot(x_axis, results['validation_0']['logloss'], label='Train')
ax.plot(x_axis, results['validation_1']['logloss'], label='Test')
ax.legend()
pyplot.ylabel('Log Loss')
pyplot.title('XGBoost Log Loss')
pyplot.show()
# plot classification error
fig, ax = pyplot.subplots()
ax.plot(x_axis, results['validation_0']['error'], label='Train')
ax.plot(x_axis, results['validation_1']['error'], label='Test')
ax.legend()
pyplot.ylabel('Classification Error')
pyplot.title('XGBoost Classification Error')
pyplot.show()

         运行此代码会在每个时期报告训练数据集和测试数据集上的分类错误。 我们可以通过在fit()函数的调用中设置verbose = False(默认值)来关闭此功能。

         注意:由于算法或评估程序的随机性,或者数值精度的差异,您的结果可能会有所不同。 考虑运行该示例几次并比较平均结果。

       将创建两个图。 第一个显示了训练和测试数据集上每个时期XGBoost模型的对数损失。

Python实践通过使用XGBoost中的尽早停止【Early Stopping】策略来避免过度拟合_第1张图片

       第二个图显示了训练和测试数据集上每个时期的XGBoost模型的分类误差。

Python实践通过使用XGBoost中的尽早停止【Early Stopping】策略来避免过度拟合_第2张图片

        通过查看对数损失图,似乎有机会尽早停止学习,可能是在20到40左右的某个地方。

       对于分类错误,我们看到了一个类似的故事,该错误似乎在第40个时代开始出现。

提前停止使用XGBoost

       XGBoost支持在固定次数的迭代后提前停止。除了指定度量和测试数据集以评估每个时期外,还必须指定一个时期数窗口,在该窗口上未观察到任何改善。 这是在early_stopping_rounds参数中指定的。例如,我们可以检查10个历元的对数损失是否改善,如下所示:

eval_set = [(X_test, y_test)]
model.fit(X_train, y_train, early_stopping_rounds=10, eval_metric="logloss", eval_set=eval_set, verbose=True)

      如果提供了多个评估数据集或多个评估指标,则尽早停止将使用列表中的最后一个。

      下面提供了一个完整的示例,说明了尽早停止的完整性。

# early stopping
from numpy import loadtxt
from xgboost import XGBClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# load data
dataset = loadtxt('pima-indians-diabetes.csv', delimiter=",")
# split data into X and y
X = dataset[:,0:8]
Y = dataset[:,8]
# split data into train and test sets
seed = 7
test_size = 0.33
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=test_size, random_state=seed)
# fit model no training data
model = XGBClassifier()
eval_set = [(X_test, y_test)]
model.fit(X_train, y_train, early_stopping_rounds=10, eval_metric="logloss", eval_set=eval_set, verbose=True)
# make predictions for test data
y_pred = model.predict(X_test)
predictions = [round(value) for value in y_pred]
# evaluate predictions
accuracy = accuracy_score(y_test, predictions)
print("Accuracy: %.2f%%" % (accuracy * 100.0))

       注意:由于算法或评估程序的随机性,或者数值精度的差异,您的结果可能会有所不同。 考虑运行该示例几次并比较平均结果。

       运行示例将提供以下输出,为简洁起见,将其截断。

[35]	validation_0-logloss:0.487962
[36]	validation_0-logloss:0.488218
[37]	validation_0-logloss:0.489582
[38]	validation_0-logloss:0.489334
[39]	validation_0-logloss:0.490969
[40]	validation_0-logloss:0.48978
[41]	validation_0-logloss:0.490704
[42]	validation_0-logloss:0.492369
Stopping. Best iteration:
[32]	validation_0-logloss:0.487297

      我们可以看到模型在第42阶段停止了训练(接近我们对学习曲线的手动判断所期望的水平),并且在第32阶段观察到了损失最大的模型。

      通常,最好选择“ early_stopping_rounds”作为训练时期总数的合理函数(在这种情况下为10%),或者尝试对应于在学习曲线图上可能观察到的拐点时间段。

你可能感兴趣的:(python实践,机器学习)