当前位置: 首页 > 科技观察

在Python中使用XGBoost和scikit-learn进行随机梯度提升

时间:2023-03-14 19:15:21 科技观察

集成决策树的一种简单技术涉及在训练数据集的子样本上训练树。可以使用训练数据中行的子集来训练称为套袋的单个树。如果在计算每个分割点时也使用训练数据行的子集,则称为随机森林。这些技术也可用于称为随机梯度提升的技术中的梯度树提升模型。在本文中,您将了解随机梯度提升以及如何在Python中使用XGBoost和scikit-learn调整采样参数。阅读这篇文章后,您将了解:如何在数据子样本上训练树以及如何将其用于梯度提升。如何使用scikit-learn在XGBoost中调整基于行的子采样。如何在XGBoost中按树和分割点调整基于列的子采样。StochasticGradientBoosting梯度提升是一个贪心的过程。向模型添加新的决策树,修正现有模型的残差。每个决策树都是使用贪婪搜索过程创建的,以选择最能最小化目标函数的分割点。这会导致树一遍又一遍地使用相同的属性,甚至使用相同的分割点。Bagging是一种用于创建决策树集合的技术,每个决策树都来自训练数据中不同的随机行子集。结果是从树的集合中获得了更好的性能,因为样本的随机性允许创建略有不同的树,从而增加了集合预测的方差。随机森林通过在选择分割点时对特征(列)进行子采样,使这一步更进一步,这进一步增加了树的整体方差。这些相同的技术可用于构建梯度提升中的决策树,这是一种称为随机梯度提升的变体。通常使用训练数据的激进子样本,例如40%到80%。教程概述在本教程中,我们将研究不同子采样技术在梯度提升中的作用。我们将采用Python的XGBoost库支持的三种不同的随机梯度提升方法,特别是:创建每棵树时,数据集中的行被二次采样。创建每棵树时,对数据集中的列进行二次采样。创建每棵树时,对数据集中每个拆分的列进行二次抽样。问题描述:Otto数据集在本教程中,我们将使用“OttoGroupProductClassificationChallenge”数据集。该数据集可从Kaggle免费获得(您需要在Kaggle注册才能下载该数据集)。您可以从“数据”页面下载训练数据集train.csv.zip,并将解压缩的train.csv文件放在您的工作目录中。该数据集描述了61,000多种产品的93个混淆细节,这些产品分为10个产品类别(例如,时尚、电子产品等)。输入属性是某种不同事件的计数。目标是将新产品预测为10个类别中每个类别的概率数组,并使用多类别对数损失(也称为交叉熵)评估模型。比赛于2015年5月结束,由于样本数量少,问题难度大,几乎不需要准备任何数据(除了将类字符串变量编码为整数),这个数据集是一个很大的数据集。一个用于XGBoost挑战。在XGBoost中调整行子采样行子采样涉及选择训练数据集的随机样本而不进行替换。可以在subsample参数中的XGBoost类的scikit-learn包装器中指定行子采样。默认值为1.0,不进行子采样。我们可以使用scikit-learn内置的网格搜索功能来评估从0.1到1.0的不同子样本值对Otto数据集的影响。[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,1.0]子样本有9个变体,每个模型将使用10折交叉验证进行评估,这意味着训练和测试9×10或90个模型。下面提供了完整的代码清单。#XGBoostonOttodataset,tunesubsamplefrompandasimportread_csvfromxgboostimportXGBClassifierfromsklearn.model_selectionimportGridSearchCVfromsklearn.model_selectionimportStratifiedKFoldfromsklearn.preprocessingimportLabelEncoderimportmatplotlibmatplotlib.use('Agg')frommatplotlibimportpyplot#loaddatadata=read_csv('train.csv')datadataset=data.values#splitdataintoXandyX=dataset[:,0:94]y=dataset[:,94]#encodestringclassvaluesasintegerslabel_encoded_y=LabelEncoder().fit_transform(y)#gridsearchmodel=XGBClassifier()subsample=[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,1.0]param_grid=dict(subsamplesubsample=subsample)kfold=StratifiedKFold(n_splits=10,shuffle=True,random_state=7)grid_search=GridSearchCV(model,param_grid,scoring="neg_log_loss",n_jobs=-1,cv=kfold)grid_result=grid_search.fit(X,label_encoded_y)#summarizeresultsprint("Best:%fusing%s"%(grid_result.best_score_,grid_result.best_params_))means=grid_result.cv_results_['mean_test_score']stds=grid_result.cv_results_['std_test_score']params=grid_result.cv_results_['params']formean,stdev,paraminzip(means,stds,params):print("%f(%f)with:%r"%(mean,stdev,param))#plotpyplot.errorbar(subsample,means,yerr=stds)pyplot.title("XGBoostsubsamplevsLogLoss")pyplot.xlabel('subsample')pyplot.ylabel('LogLoss')pyplot.savefig('subsample.png')运行此示例将打印最佳配置以及每个测试配置的对数损失注意:您的结果可能因算法或评估器中的随机性或数值精度的差异而有所不同。考虑运行该示例几次并比较平均结果。我们可以看到得到的最好结果是0.3,或者用30%的训练数据集样本来训练树。最佳:-0.000647使用{'subsample':0.3}-0.001156(0.000286)with:{'subsample':0.1}-0.000765(0.000430)with:{'subsample':0.2}-0.000647(0.000471)with:{'subsample'':0.3}-0.000659(0.000635)with:{'subsample':0.4}-0.000717(0.000849)with:{'subsample':0.5}-0.000773(0.000998)with:{'subsample':0.6}-0.000877(0.001179)with:{'subsample':0.7}-0.001007(0.001371)with:{'subsample':0.8}-0.001239(0.001730)with:{'subsample':1.0}我们可以绘制这些均值和标准差对数损失值,以更好地了解性能如何随子样本值变化。我们可以看到30%确实具有最好的平均性能,但是我们也可以看到随着比例的增加,性能的方差显着增加。有趣的是,所有子样本值的平均性能优于没有子采样的平均性能(子样本=1.0)。XGBoost中的树调整列二次抽样我们还可以在增强模型中创建每个决策树之前创建要使用的特征(或列)的随机样本。在scikit-learn的XGBoost包装器中,这由colsample_bytree参数控制。默认值为1.0,这意味着使用每个决策树中的所有列。我们可以在0.1和1.0之间评估colsample_bytree的值,以0.1为增量。[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,1.0]完整实例如下:#XGBoostonOttodataset,tunecolsample_bytreefrompandasimportread_csvfromxgboostimportXGBClassifierfromsklearn.model_selectionimportGridSearchCVfromsklearn.model_selectionimportStratifiedKFoldfromsklearn.preprocessingimportLabelEncoderimportmatplotlibmatplotlib.use('Agg')frommatplotlibimportpyplot#loaddatadata=read_csv('train.csv')datadataset=data.values#splitdataintoXandyX=dataset[:,0:94]y=dataset[:,94]#encodestringclassvaluesasintegerslabel_encoded_y=LabelEncoder().fit_transform(y)#gridsearchmodel=XGBClassifier()colsample_bytree=[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,1.0]param_grid=dict(colsample_bytreecolsample_bytree=colsample_bytree)kfold=StratifiedKFold(n_splits=10,shuffle=True,random_state=7)grid_search=GridSearchCV(model,param_grid,scoring="neg_log_loss",n_jobs=-1,cv=kfold)grid_result=grid_search.fit(X,label_encoded_y)#summarizeresultsprint("最佳:%融合%s"%(grid_result.best_score_,grid_result.best_params_))means=grid_result.cv_results_['mean_test_score']stds=grid_result.cv_results_['std_test_score']params=grid_result.cv_results_['params']formean,stdev,paraminzip(means,stds,params):print("%f(%f)with:%r"%(mean,stdev,param))#plotpyplot.errorbar(colsample_bytree,means,yerr=stds)pyplot.title("XGBoostcolsample_bytreevsLogLoss")pyplot.xlabel('colsample_bytree')pyplot.ylabel('LogLoss')pyplot.savefig('colsample_bytree.png')运行此示例将打印最佳配置以及每个测试配置的对数损失注意:由于算法或评估器中的随机性,或差异数值精度,您的结果可能会有所不同。我们可以看到模型的最佳性能是colsample_bytree=1.0。这表明二次抽样不会增加问题的价值。最佳:-0.001239使用{'colsample_bytree':1.0}-0.298955(0.002177)with:{'colsample_bytree':0.1}-0.092441(0.000798)with:{'colsample_bytree':0.2}-0.029993(0.000459coampls)with':0.3}-0.010435(0.000669)with:{'colsample_bytree':0.4}-0.004176(0.000916)with:{'colsample_bytree':0.5}-0.002614(0.001062)with:{'colsample_bytree':0.106}-0.02(0.01)with:{'colsample_bytree':0.7}-0.001306(0.001435)with:{'colsample_bytree':0.8}-0.001239(0.001730)with:{'colsample_bytree':1.0}绘制结果,我们可以看到模型的固定部分的性能(至少在这个尺度上),值为0.5到1.0。通过拆分调整XGBoost中的列子采样我们可以在决策树的每个拆分中对它们进行子采样,而不是为每棵树对列进行一次子采样。原则上,这是随机森林中使用的方法。我们可以在scikit-learn的XGBoost包装类的colsample_bylevel参数中设置用于每次拆分的列样本的大小。和以前一样,我们将比率从10%更改为默认值100%。下面提供了完整的代码清单。#XGBoostonOttodataset,tunecolsample_bylevelfrompandasimportread_csvfromxgboostimportXGBClassifierfromsklearn.model_selectionimportGridSearchCVfromsklearn.model_selectionimportStratifiedKFoldfromsklearn.preprocessingimportLabelEncoderimportmatplotlibmatplotlib.use('Agg')frommatplotlibimportpyplot#loaddatadata=read_csv('train.csv')datadataset=data.values#splitdataintoXandyX=dataset[:,0:94]y=dataset[:,94]#encodestringclassvaluesasintegerslabel_encoded_y=LabelEncoder().fit_transform(y)#gridsearchmodel=XGBClassifier()colsample_bylevel=[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,1.0]param_grid=dict(colsample_bylevelcolsample_bylevel=colsample_bylevel)kfold=StratifiedKFold(n_splits=10,shuffle=True,random_state=7)grid_search=GridSearchCV(model,param_grid,scoring="neg_log_loss",n_jobs=-1,cv=kfold)grid_result=grid_search.fit(X,label_encoded_y)#summarizeresultsprint("Best:%fusing%s"%(grid_result.best_score_,grid_result.best_params_))means=grid_result.cv_results_['mean_test_score']stds=grid_result.cv_results_['std_test_score']params=grid_result.cv_results_['params']formean,stdev,paraminzip(means,stds,params):print("%f(%f)与:%r"%(mean,stdev,param))#plotpyplot.errorbar(colsample_bylevel,means,yerr=stds)pyplot.title("XGBoostcolsample_bylevelvsLogLoss")pyplot.xlabel('colsample_bylevel')pyplot.ylabel('LogLoss')pyplot.savefig('colsample_bylevel.png')运行此示例将打印最佳配置以及每个测试配置的对数损失注意:由于算法或评估器中的随机性,或数值精度的差异,您的结果可能会有所不同不同的。考虑运行该示例几次并比较平均结果。我们可以看到,将colsample_bylevel设置为70%可获得最佳结果,导致(反向)对数损失为-0.001062,这优于将每棵树的列采样设置为100%时看到的-0.001239。如果每棵树的结果表明100%的列,建议不要放弃列二次抽样,而是尝试通过拆分进行列二次抽样。最佳:-0.001062using{'colsample_bylevel':0.7}-0.159455(0.007028)with:{'colsample_bylevel':0.1}-0.034391(0.003533)with:{'colsample_bylevel':0.2}-0.007619(0.000:451_covelsampls)with':0.3}-0.002982(0.000726)with:{'colsample_bylevel':0.4}-0.001410(0.000946)with:{'colsample_bylevel':0.5}-0.001182(0.001144)with:{'colsample_bylevel':0.10}0.62(02.01)with:{'colsample_bylevel':0.7}-0.001071(0.001427)with:{'colsample_bylevel':0.8}-0.001239(0.001730)with:{'colsample_bylevel':1.0}我们可以绘制每个colsample_bylevel变化的性能。结果表明,在此尺度上的值为0.3之后,方差相对较低,性能似乎趋于平稳。