Python降低XGBoost 过度拟合多种方法

之前已经讲过机器学习的 XGBoost 算法简介
XGBoost feature importance特征重要性-实战印第安人糖尿病数据集
今天来讲解xgboost过度拟合问题。

过度拟合是机器学习建模经常遇到的问题,也是棘手问题,甚至数据科学岗位面试时候经常会遇到这类难题。大家不要怕,接下来我会详细讲述python xgboost如何降低过度拟合方法和其它更好方法。

xgboost建模中,如果变量数量太多,模型容易过度拟合,英文术语为overfitting,如下图右。

如果变量太少,容易欠拟合,英文术语为underfitting,如下图左。

如果变量刚好合适,模型拟合就会比较好,如下图中。

图片

我们用xgboost建模时应当如何避免过度拟合呢?

1.我们应首先观察模型变量是否太多,是否包含大量无效变量(噪音变量)?如果模型噪音变量太多,就先变量筛选,踢除无效变量,或用降维手段测试效果。这一条是至关重要的前提,如果做不好变量筛选和降维,后续方法效果会大打折扣。

2.我们可以设置xgboost中eval_set,eval_metric,early_stopping_rounds参数,来减轻过度拟合。如果因数据原因,完全消除过度拟合是不可能的。

3.采用其他集成树算法进一步减轻过度拟合,例如对称树算法catboost。对称树算法catboost有天然对抗过度拟合优点,之后我会安排时间讲解catboost算法。

图片

接下来我将描述如何在 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 ”用于多类对数损失(交叉熵)。

  • error ”表示分类错误。

  • auc ”表示ROC曲线下的面积。

XGBoost 参数网页的“学习任务参数”部分提供了完整列表。

例如,我们可以演示如何在皮马印第安人糖尿病数据集上跟踪 XGBoost 模型的训练性能。

下载数据集文件并将其放在您当前的工作目录中。

  • 数据集下载链接:

    https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.csv

  • 数据集详细信息如下:

1. Title: Pima Indians Diabetes Database

2. Sources:
   (a) Original owners: National Institute of Diabetes and Digestive and
                        Kidney Diseases
   (b) Donor of database: Vincent Sigillito (vgs@aplcen.apl.jhu.edu)
                          Research Center, RMI Group Leader
                          Applied Physics Laboratory
                          The Johns Hopkins University
                          Johns Hopkins Road
                          Laurel, MD 20707
                          (301) 953-6231
   (c) Date received: 9 May 1990

3. Past Usage:
    1. Smith,~J.~W., Everhart,~J.~E., Dickson,~W.~C., Knowler,~W.~C., \&
       Johannes,~R.~S. (1988). Using the ADAP learning algorithm to forecast
       the onset of diabetes mellitus.  In {\it Proceedings of the Symposium
       on Computer Applications and Medical Care} (pp. 261--265).  IEEE
       Computer Society Press.

       The diagnostic, binary-valued variable investigated is whether the
       patient shows signs of diabetes according to World Health Organization
       criteria (i.e., if the 2 hour post-load plasma glucose was at least 
       200 mg/dl at any survey  examination or if found during routine medical
       care).   The population lives near Phoenix, Arizona, USA.

       Results: Their ADAP algorithm makes a real-valued prediction between
       0 and 1.  This was transformed into a binary decision using a cutoff of 
       0.448.  Using 576 training instances, the sensitivity and specificity
       of their algorithm was 76% on the remaining 192 instances.

4. Relevant Information:
      Several constraints were placed on the selection of these instances from
      a larger database.  In particular, all patients here are females at
      least 21 years old of Pima Indian heritage.  ADAP is an adaptive learning
      routine that generates and executes digital analogs of perceptron-like
      devices.  It is a unique algorithm; see the paper for details.

5. Number of Instances: 768

6. Number of Attributes: 8 plus class 

7. For Each Attribute: (all numeric-valued)
   1. Number of times pregnant
   2. Plasma glucose concentration a 2 hours in an oral glucose tolerance test
   3. Diastolic blood pressure (mm Hg)
   4. Triceps skin fold thickness (mm)
   5. 2-Hour serum insulin (mu U/ml)
   6. Body mass index (weight in kg/(height in m)^2)
   7. Diabetes pedigree function
   8. Age (years)
   9. Class variable (0 or 1)

8. Missing Attribute Values: Yes

9. Class Distribution: (class value 1 is interpreted as "tested positive for
   diabetes")

   Class Value  Number of instances
   0            500
   1            268

10. Brief statistical analysis:

    Attribute number:    Mean:   Standard Deviation:
    1.                     3.8     3.4
    2.                   120.9    32.0
    3.                    69.1    19.4
    4.                    20.5    16.0
    5.                    79.8   115.2
    6.                    32.0     7.9
    7.                     0.5     0.3
    8.                    33.2    11.8

完整示例如下:

# 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))

运行此示例在 67% 的数据上训练模型,并在 33% 的测试数据集上评估每个训练时期的模型。

每次迭代都会报告分类错误,最后在最后报告分类精度。

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

下面提供了输出,为简洁起见被截断。我们可以看到,每次训练迭代都会报告分类错误(在将每个提升树添加到模型之后)。

...
[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 参数提供一组指标来指定更多的评估指标来评估和收集。

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

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

#原创公众号:python风控模型
# 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 模型在训练和测试数据集上每个时期的对数损失。

图片

XGBoost 学习曲线对数损失

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

图片

XGBoost 学习曲线分类错误

从查看 logloss 图来看,似乎有机会提前停止学习,可能在 20 到 40 纪元左右。

我们看到了类似的分类错误故事,其中错误似乎在第 40 轮左右回升。

使用 XGBoost 提前停止

XGBoost 支持在固定次数的迭代后提前停止。

除了指定用于评估每个 epoch 的度量和测试数据集之外,您还必须指定一个窗口,其中包含没有观察到改进的 epoch 数。这是在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

我们可以看到模型在 epoch 42 停止训练(接近我们手动判断学习曲线的预期),并且在 epoch 32 观察到损失最好的模型。

通常选择early_stopping_rounds作为训练时期总数的合理函数(在这种情况下为 10%)或尝试对应于可能在学习曲线图上观察到的拐点周期是一个好主意。

总结

在这篇文章中,我们了解到了:

  • 关于在模型过度拟合训练数据之前停止模型训练的提前停止技术。

  • 如何在训练期间监控 XGBoost 模型的性能并绘制学习曲线。

  • 如何在训练 XGBoost 模型时配置提前停止。


xgboost过度拟合知识就为大家介绍到这里了,欢迎各位同学报名<python风控建模实战lendingclub>,学习更多集成树算法相关知识 https://edu.csdn.net/course/detail/30742

版权声明:文章来自公众号(python风控模型),未经许可,不得抄袭。遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

python机器学习建模

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值