机器学习 XGBoost和Random Forest

前言

最近需要做回归分析,使用到XGBoostRandom Forest。一开始选择Random Forest,原因有二,一是自己对决策树比较熟悉,随机森林集成多个决策树;二是决策树无需对数据进行归一化或者标准化。在此也引出需要探讨一个问题:在推理阶段如果只有一条数据做推理,如何做归一化或者标准化?在实验当中,使用随机回归森林的算法取得非常不错的结果,这个结果接近百分百的准确率,MAE、MSE、RMSE等相关指标都非常低。然后使用线性模型XGBoost的linear模型进行训练,结果却不理想。一个天,一个地,觉得还需要好好探讨里面的数据逻辑。本篇博客主要讲得不是数据里面的逻辑,毕竟数据是机密的。本博客主要是对XGBoostRandom Forest进行复盘。

在此延伸一下机器学习中的bagging和boosting思想。

bagging

Bagging又称为自举汇聚法。在同一个数据集中不同样本上拟合多种学习器,得到的结果进行平均并且通过改变训练数据来寻找多样化集成成员。Bagging思想是在原始数据集上通过有放回抽样,重新选择N个新数据集来分别训练N个分类器的集成技术。模型训练数据中允许存在重复数据。随机森林主要是应用到这种思想。
在这里插入图片描述
在这里插入图片描述

Boosting

Boosting方法基于的思想:对于一个复杂任务来说,将多个专家的判断进行适当的综合所得出的判断,要比其中任何一个专家单独的判断好,就是“三个臭皮匠顶个诸葛亮”的道理。在1990年,Schapire证明一个类强可学习与一个类弱可学习是等价的,即一个类是强可学习的充分必要条件是这个类是弱可学习的。这样一来,如果已经发现了“弱学习算法”,那么能否将它提升为“强学习算法”。发现弱学习算法通常要比发现强学习算法容易得多,那么如何具体实施提升,便成为开发提升方法时所要解决的问题。经典的具有代表的提升方法是AdaBoost算法。对于分类问题而言,给定一个训练样本集,求比较粗糙的分类规则(弱分类器)要比求精确的分类规则(强分类器)容易得多。Boosting集成就是从弱学习算法出发,反复学习,得到一系列弱分类器(又称基本分类器),然后组合这些弱分类器,构成一个强分类器。一种Adaboost算法如下图所示:
在这里插入图片描述

Random Forest

随机森林以集成学习的思想将多个决策树集成的算法。随机森林算法体现两个关键词:“随机”和“森林”,“森林”很好理解,就是集成多个决策树。“随机”会在下文提到,就是多个决策树决策的结果,随机森林是如何进行决策的。随机森林具有以下几个特点:

  • 具有较好的准确率(It is unexcelled in accuracy among current algorithms)
  • 能够有效处理大型数据集(It runs efficiently on large data bases)
  • 能够处理高维特征样本,无需降维(It can handle thousands of input variables without variable deletion)
  • 能够评估各个特征的重要性(It gives estimates of what variables are important in the classification)
  • 在树生成过程中,能够获取内部生成误差的一种无偏估计
  • 能够处理特征值缺省问题

关于随机森林的介绍就到这,不再展开了。关于决策树的更多内容,可以参考:Random Forest。接下来就讨论如何实现决策树。

随机森林实现

决策树可以应用于分类和回归任务当中,在sklearn里的有RandomForestClassifierRandomForestRegressor两个类。

RandomForestClassifier

class sklearn.ensemble.RandomForestClassifier(n_estimators=100, *, criterion=‘gini’, max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=‘auto’, max_leaf_nodes=None, min_impurity_decrease=0.0, bootstrap=True, oob_score=False, n_jobs=None, random_state=None, verbose=0, warm_start=False, class_weight=None, ccp_alpha=0.0, max_samples=None)[source]

相关参数说明:

参数名类型默认值说明
n_estimatorsint100随机森林中树的数量
criterion{“gini”, “entropy”}gini衡量指标,只能选择gini或者entropy
max_depthintnone设置树的深度,假设为none,树会分裂到所有叶子节点为纯或者叶子数量少于设置的min_samples_split
min_samples_splitint or float2分裂结点时要求的最小样本数量,假设为float,则数量为ceil(min_samples_split * n_samples)
min_samples_leafint or float1当样本数量小于该设置值,则不再分裂。假设为float,则该值为ceil(min_samples_leaf * n_samples)
min_weight_fraction_leaffloat0.0叶节点所需的(所有输入样本)权重总和的最小加权分数
max_features{“auto”, “sqrt”, “log2”}auto寻找最佳分割时要考虑的特征数量
max_leaf_nodesintNone以最佳优先方式生长具有最大叶节点的树。最佳节点定义为杂质的相对减少。如果没有,则叶节点数不限。
min_impurity_decreasefloat0如果此分割导致杂质减少大于或等于此值,则节点将被分割。
bootstrapboolboolTrueWhether bootstrap samples are used when building trees. If False, the whole dataset is used to build each tree.
oob_scoreboolboolFalse是否使用现成的样本来估计综合得分。仅当bootstrap=True时可用。
n_jobsintintNone并行运行数
random_stateintintNone随机性设置
verboseintint0显示的信息数
warm_startboolboolFalse当设置为True时,重用上一次调用的解决方案进行拟合,并向集合中添加更多估计器,否则,只需训练整个全新的随机森林
class_weight{“balanced”, “balanced_subsample”}, dict or list of dictsNone设置类的权重
ccp_alphanonnon-negative float0.0复杂度参数用于最小成本复杂度修剪。将选择成本复杂度最大且小于ccp_alpha的子树。默认情况下,不执行修剪。
max_samplesint or floatNone最大样本数

在这里插入图片描述

例子

>>> from sklearn.ensemble import RandomForestClassifier
>>> from sklearn.datasets import make_classification
>>> X, y = make_classification(n_samples=1000, n_features=4,
...                            n_informative=2, n_redundant=0,
...                            random_state=0, shuffle=False)
>>> clf = RandomForestClassifier(max_depth=2, random_state=0)
>>> clf.fit(X, y)
RandomForestClassifier(...)
>>> print(clf.predict([[0, 0, 0, 0]]))
[1]

最后可以通过浏览sklearn.ensemble.RandomForestClassifier获取更多信息。

RandomForestRegressor

class sklearn.ensemble.RandomForestRegressor(n_estimators=100, *, criterion=‘squared_error’, max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=‘auto’, max_leaf_nodes=None, min_impurity_decrease=0.0, bootstrap=True, oob_score=False, n_jobs=None, random_state=None, verbose=0, warm_start=False, ccp_alpha=0.0, max_samples=None)[source]

该方法的参数跟上面的分类随机森林差不多,主要的区别是criterion,回归随机森林的取值如下:

参数名类型默认值说明
criterion{“squared_error”, “absolute_error”, “poisson”}squared_error分裂标准取值

总结

RandomForestClassifierRandomForestRegressor进行参数总结如下:

  • 控制bagging框架的参数
  1. estimators:随机森林中树的棵树,即要生成多少个基学习器(决策树)。
  2. boostrap:是否采用自助式采样生成采样集。
  3. obb_score:是否使用袋外数据来估计模型的有效性。
  • 控制决策树的参数
  1. criterion:选择最优划分属性的准则,默认是"gini",可选"entropy"。
  2. max_depth:决策树的最大深度
  3. max_features:随机抽取的候选划分属性集的最大特征数(属性采样)
  4. min_samples_split:内部节点再划分所需最小样本数。默认是2,可设置为整数或浮点型小数。
  5. min_samples_leaf:叶子节点最少样本数。默认是1,可设置为整数或浮点型小数。
  6. max_leaf_nodes:最大叶子结点数。默认是不限制。
  7. min_weight_fraction_leaf:叶子节点最小的样本权重和。默认是0。
  8. min_impurity_split:节点划分最小不纯度。
  • 其他参数:
  1. n_jobs:并行job的个数
  2. verbose:是否显示任务进程

XGBoost算法

在Kaggle数据比赛中,XGBoost算法是用到比较多的,它的主要思想是boosting思想。XGBoost本质上是一个梯度提升树。

GBDT

提升树是迭代多棵回归树来共同决策。当采用平方误差损失函数时,每一棵回归树学习之前树的结论和残差,拟合得到一个当前的残差回归树,残差的公式是:残差=真实值-预测值。提升树即是整个迭代过程生成的回归树的累加。

在这里插入图片描述

梯度提升决策树算法:
在这里插入图片描述

LightGBM

GBDT (Gradient Boosting Decision Tree) 是机器学习中一个长盛不衰的模型,其主要思想是利用弱分类器(决策树)迭代训练以得到最优模型,该模型具有训练效果好、不易过拟合等优点,已经被广泛应用于多分类、点击率预测以及搜索排序等任务。而LightGBM(Light Gradient Boosting Machine)是一个实现GBDT算法的框架,支持高效率的并行训练,并且具有更快的训练速度、更低的内存消耗、更好的准确率、支持分布式可以快速处理海量数据等优点。

LightGBM在传统的GBDT算法上进行了如下优化:

  • 基于Histogram的决策树算法。
  • 单边梯度采样 Gradient-based One-Side Sampling(GOSS):使用GOSS可以减少大量只具有小梯度的数据实例,这样在计算信息增益的时候只利用剩下的具有高梯度的数据就可以了,相比XGBoost遍历所有特征值节省了不少时间和空间上的开销。
  • 互斥特征捆绑 Exclusive Feature Bundling(EFB):使用EFB可以将许多互斥的特征绑定为一个特征,这样达到了降维的目的。
  • 带深度限制的Leaf-wise的叶子生长策略
  • 直接支持类别特征(Categorical Feature)
  • 支持高效并行
  • Cache命中率优化

基本原理

基于Histogram的决策树算法

Histogram algorithm应该翻译为直方图算法,直方图算法的基本思想是:先把连续的浮点特征值离散化成 k k k个整数,同时构造一个宽度为 k k k的直方图。在遍历数据的时候,根据离散化后的值作为索引在直方图中累积统计量,当遍历一次数据后,直方图累积了需要的统计量,然后根据直方图的离散值,遍历寻找最优的分割点。

在这里插入图片描述
直方图算法简单理解为:首先确定对于每一个特征需要多少个箱子(bin)并为每一个箱子分配一个整数;然后将浮点数的范围均分成若干区间,区间个数与箱子个数相等,将属于该箱子的样本数据更新为箱子的值;最后用直方图(#bins)表示。看起来很高大上,其实就是直方图统计,将大规模的数据放在了直方图中。

当然,Histogram算法并不是完美的。由于特征被离散化后,找到的并不是很精确的分割点,所以会对结果产生影响。但在不同的数据集上的结果表明,离散化的分割点对最终的精度影响并不是很大,甚至有时候会更好一点。原因是决策树本来就是弱模型,分割点是不是精确并不是太重要;较粗的分割点也有正则化的效果,可以有效地防止过拟合;即使单棵树的训练误差比精确分割的算法稍大,但在梯度提升(Gradient Boosting)的框架下没有太大的影响。

直方图做差加速

LightGBM另一个优化是Histogram(直方图)做差加速。一个叶子的直方图可以由它的父亲节点的直方图与它兄弟的直方图做差得到,在速度上可以提升一倍。通常构造直方图时,需要遍历该叶子上的所有数据,但直方图做差仅需遍历直方图的k个桶。在实际构建树的过程中,LightGBM还可以先计算直方图小的叶子节点,然后利用直方图做差来获得直方图大的叶子节点,这样就可以用非常微小的代价得到它兄弟叶子的直方图。

在这里插入图片描述

带深度限制的 Leaf-wise 算法

在Histogram算法之上,LightGBM进行进一步的优化。首先它抛弃了大多数GBDT工具使用的按层生长 (level-wise) 的决策树生长策略,而使用了带有深度限制的按叶子生长 (leaf-wise) 算法。

XGBoost 采用 Level-wise 的增长策略,该策略遍历一次数据可以同时分裂同一层的叶子,容易进行多线程优化,也好控制模型复杂度,不容易过拟合。但实际上Level-wise是一种低效的算法,因为它不加区分的对待同一层的叶子,实际上很多叶子的分裂增益较低,没必要进行搜索和分裂,因此带来了很多没必要的计算开销。
在这里插入图片描述
LightGBM采用Leaf-wise的增长策略,该策略每次从当前所有叶子中,找到分裂增益最大的一个叶子,然后分裂,如此循环。因此同Level-wise相比,Leaf-wise的优点是:在分裂次数相同的情况下,Leaf-wise可以降低更多的误差,得到更好的精度;Leaf-wise的缺点是:可能会长出比较深的决策树,产生过拟合。因此LightGBM会在Leaf-wise之上增加了一个最大深度的限制,在保证高效率的同时防止过拟合。

在这里插入图片描述

单边梯度采样算法

Gradient-based One-Side Sampling 应该被翻译为单边梯度采样(GOSS)。GOSS算法从减少样本的角度出发,排除大部分小梯度的样本,仅用剩下的样本计算信息增益,它是一种在减少数据量和保证精度上平衡的算法。

AdaBoost中,样本权重是数据重要性的指标。然而在GBDT中没有原始样本权重,不能应用权重采样。幸运的是,我们观察到GBDT中每个数据都有不同的梯度值,对采样十分有用。即梯度小的样本,训练误差也比较小,说明数据已经被模型学习得很好了,直接想法就是丢掉这部分梯度小的数据。然而这样做会改变数据的分布,将会影响训练模型的精确度,为了避免此问题,提出了GOSS算法。

在这里插入图片描述

实现


from lightgbm import LGBMClassifier
from sklearn.metrics import accuracy_score
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.externals import joblib

# 加载数据
iris = load_iris()
data = iris.data
target = iris.target

# 划分训练数据和测试数据
X_train, X_test, y_train, y_test = train_test_split(data, target, test_size=0.2)

# 模型训练
gbm = LGBMClassifier(num_leaves=31, learning_rate=0.05, n_estimators=20)
gbm.fit(X_train, y_train, eval_set=[(X_test, y_test)], early_stopping_rounds=5)

# 模型存储
joblib.dump(gbm, 'loan_model.pkl')
# 模型加载
gbm = joblib.load('loan_model.pkl')

# 模型预测
y_pred = gbm.predict(X_test, num_iteration=gbm.best_iteration_)

# 模型评估
print('The accuracy of prediction is:', accuracy_score(y_test, y_pred))

# 特征重要度
print('Feature importances:', list(gbm.feature_importances_))

# 网格搜索,参数优化
estimator = LGBMClassifier(num_leaves=31)
param_grid = {
    'learning_rate': [0.01, 0.1, 1],
    'n_estimators': [20, 40]
}
gbm = GridSearchCV(estimator, param_grid)
gbm.fit(X_train, y_train)
print('Best parameters found by grid search are:', gbm.best_params_)

import pandas as pd
from sklearn.model_selection import train_test_split
import lightgbm as lgb
from sklearn.metrics import mean_absolute_error
from sklearn.preprocessing import Imputer

# 1.读文件
data = pd.read_csv('./dataset/train.csv')

# 2.切分数据输入:特征 输出:预测目标变量
y = data.SalePrice
X = data.drop(['SalePrice'], axis=1).select_dtypes(exclude=['object'])

# 3.切分训练集、测试集,切分比例7.5 : 2.5
train_X, test_X, train_y, test_y = train_test_split(X.values, y.values, test_size=0.25)

# 4.空值处理,默认方法:使用特征列的平均值进行填充
my_imputer = Imputer()
train_X = my_imputer.fit_transform(train_X)
test_X = my_imputer.transform(test_X)

# 5.调用LightGBM模型,使用训练集数据进行训练(拟合)
# Add verbosity=2 to print messages while running boosting
my_model = lgb.LGBMRegressor(objective='regression', num_leaves=31, learning_rate=0.05, n_estimators=20,
                             verbosity=2)
my_model.fit(train_X, train_y, verbose=False)

# 6.使用模型对测试集数据进行预测
predictions = my_model.predict(test_X)

# 7.对模型的预测结果进行评判(平均绝对误差)
print("Mean Absolute Error : " + str(mean_absolute_error(predictions, test_y)))

具体可参考:https://mp.weixin.qq.com/s/65r7TY2mUg2OSPIO9r4qCg

XGBoost

XGBoost的核心算法思想是:

  1. 不断地添加树,不断地进行特征分裂来生长一棵树,每次添加一棵树,其实是学习一个新函数f(x),去拟合上次预测的残差。
  2. 当训练完得到K棵树,要预测一个样本的分数。其实就是根据这个样本的特征,在每棵树中落到对应的一个叶子节点,每个叶子节点就对应一个分数
  3. 最后只需要将每棵树对应的分数加起来就是该样本的预测值。

具体的理论可以参考XGBoost的论文:XGBoost: A Scalable Tree Boosting System以及XGBoost官网的介绍:XGBoost/tutorials

XGBoost实现

一个简单的xgboost的实现:

import xgboost as xgb
# read in data
dtrain = xgb.DMatrix('demo/data/agaricus.txt.train')
dtest = xgb.DMatrix('demo/data/agaricus.txt.test')
# specify parameters via map
param = {'max_depth':2, 'eta':1, 'objective':'binary:logistic' }
num_round = 2
bst = xgb.train(param, dtrain, num_round)
# make prediction
preds = bst.predict(dtest)

XGBoost的参数分为三种。

通用参数:

通用参数包含两种类型的booster:tree和linear。

  • booster:使用哪个弱分类器进行训练,默认gbtree,取值有:gbtree、gblinear或dart
  • nthread:用于运行XGBoost的并行线程数,默认为最大可用线程数
  • verbosity:打印运行信息的详细程度:0为静默、1为警告,2信息,3调试。
  • Tree Booster的参树:
    1. eta(learning_rate):learning rate,在更新中使用步长收缩以防止过度拟合,默认=0.3,取值范围为[0,1]。典型一般设置为0.01-0.2。
    2. gamma(min_split_loss):默认为0,分裂结点时,损失函数减少值只有大于等于gamma节点才分裂,gamma值越大,算法越保守,越不容易过拟合,但性能就不一定能保证,需要平衡。
    3. max_depth:默认为6,一棵树的最大深度。增加此值将使模型更加复杂,并且更可能过度拟合。取值范围为大于等于0。
    4. min_delta_step:默认为0,允许每个叶子输出的最大增量步长。如果将该值设置为0,则表示没有约束。如果将其设置为正值,则可以帮助使更新步骤更加保守。通常不需要此参数,但是当类极度不平衡时,它可能有助于逻辑回归。将其设置为1-10的值可能有助于控制更新。
    5. min_child_weight:默认值= 1,如果新分裂的节点的样本权重和小于min_child_weight则停止分裂 。这个可以用来减少过拟合,但是也不能太高,会导致欠拟合。
    6. max_delta_step:默认= 0,允许每个叶子输出的最大增量步长。如果将该值设置为0,则表示没有约束。如果将其设置为正值,则可以帮助使更新步骤更加保守。通常不需要此参数,但是当类极度不平衡时,它可能有助于逻辑回归。将其设置为1-10的值可能有助于控制更新。
    7. subsample:默认值= 1,构建每棵树对样本的采样率,如果设置成0.5,XGBoost会随机选择一半的样本作为训练集。
    8. sampling_method:默认= uniform,用于对训练实例进行采样的方法。
    9. colsample_bytree:默认= 1,列采样率,也就是特征采样率。
    10. lambda(reg_lambda):默认=1,L2正则化权重项。增加此值将使模型更加保守。
    11. alpha(reg_alpha):默认= 0,权重的L1正则化项。增加此值将使模型更加保守。
    12. tree_method:默认=auto,XGBoost中使用的树构建算法。
    13. scale_pos_weight:控制正负权重的平衡,这对于不平衡的类别很有用。Kaggle竞赛一般设置sum(negative instances) / sum(positive instances),在类别高度不平衡的情况下,将参数设置大于0,可以加快收敛。
    14. num_parallel_tree:默认=1,每次迭代期间构造的并行树的数量。此选项用于支持增强型随机森林。
    15. monotone_constraints:可变单调性的约束,在某些情况下,如果有非常强烈的先验信念认为真实的关系具有一定的质量,则可以使用约束条件来提高模型的预测性能。(例如params_constrained[‘monotone_constraints’] = “(1,-1)”,(1,-1)我们告诉XGBoost对第一个预测变量施加增加的约束,对第二个预测变量施加减小的约束。)
  • Linear Booster的参数
    1. lambda(reg_lambda):默认= 0,L2正则化权重项。增加此值将使模型更加保守。归一化为训练示例数。
    2. alpha(reg_alpha):默认= 0,权重的L1正则化项。增加此值将使模型更加保守。归一化为训练示例数。
    3. updater:默认= shotgun。shotgun:基于shotgun算法的平行坐标下降算法。使用“ hogwild”并行性,因此每次运行都产生不确定的解决方案。coord_descent:普通坐标下降算法。同样是多线程的,但仍会产生确定性的解决方案。
    4. feature_selector:默认= cyclic。特征选择和排序方法。cyclic:通过每次循环一个特征来实现的。shuffle:类似于cyclic,但是在每次更新之前都有随机的特征变换。random:一个随机(有放回)特征选择器。greedy:选择梯度最大的特征。(贪婪选择)thrifty:近似贪婪特征选择(近似于greedy)
    5. top_k:要选择的最重要特征数(在greedy和thrifty内)

任务参数

任务参数用来控制理想的优化目标和每一步结果的度量方法。

  • objective:默认=reg:squarederror,表示最小平方误差。
    1. reg:squarederror:最小平方误差
    2. reg:squaredlogerror:对数平方损失。
    3. reg:logistic:逻辑回归
    4. reg:pseudohubererror:使用伪Huber损失进行回归,这是绝对损失的两倍可微选择。
    5. binary:logistic:二元分类的逻辑回归,输出概率。
    6. binary:logitraw:用于二进制分类的逻辑回归,逻辑转换之前的输出得分
    7. binary:hinge:二进制分类的铰链损失。
    8. count:poisson –计数数据的泊松回归,泊松分布的输出平均值。
    9. survival:cox:针对正确的生存时间数据进行Cox回归(负值被视为正确的生存时间)。
    10. survival:aft:用于检查生存时间数据的加速故障时间模型。
    11. aft_loss_distribution:survival:aft和aft-nloglik度量标准使用的概率密度函数。
    12. multi:softmax:设置XGBoost以使用softmax目标进行多类分类,还需要设置num_class(类数)
    13. multi:softprob:与softmax相同,但输出向量,可以进一步重整为矩阵。结果包含属于每个类别的每个数据点的预测概率。
    14. rank:pairwise:使用LambdaMART进行成对排名,从而使成对损失最小化。
    15. rank:ndcg:使用LambdaMART进行列表式排名,使标准化折让累积收益(NDCG)最大化。
    16. rank:map:使用LambdaMART进行列表平均排名,使平均平均精度(MAP)最大化。
    17. reg:gamma:使用对数链接进行伽马回归。输出是伽马分布的平均值。
    18. reg:tweedie:使用对数链接进行Tweedie回归。
  • eval_metric:验证数据的评估指标,将根据目标分配默认指标(回归均方根,分类误差,排名的平均平均精度),用户可以添加多个评估指标
    1. rmse,均方根误差;rmsle:均方根对数误差; mae:平均绝对误差;mphe:平均伪Huber错误;logloss:负对数似然;error:二进制分类错误率;
    2. merror:多类分类错误率;mlogloss:多类logloss;auc:曲线下面积; aucpr:PR曲线下的面积;ndcg:归一化累计折扣;map:平均精度;
  • seed :随机数种子,[默认= 0]。

命令行参数

一个简单的XGBoost例子:

# Method for Hyperparameter Tuning
from sklearn.metrics import mean_squared_log_error
def get_best_xgb_model(X_c,y_c):
    X_train_c, X_val_c, y_train_c, y_val_c = train_test_split(X_c, y_c, test_size=0.30, random_state=42)
    print('XGBoost Hyper Parameter Tunning')
    min_child_samples=[5,10,20,50,70]
    loss=[]
    loss1=[]
    loss2=[]
    loss3=[]
    loss4=[]
    for n in min_child_samples:
        xgb_c=XGBRegressor(n_iterators=1000,min_child_samples=n)
        xgb_c.fit(X_train_c,y_train_c)
        y_pred=pred(xgb_c,X_val_c)
        if ((y_val_c >= 0).all() and (y_pred >= 0).all()):
            loss.append(mean_squared_log_error(y_pred,y_val_c))
            #print('min_child_samples:',n,'msle:',mean_squared_log_error(y_pred,y_val_c))
    print('Best min_child_samples:',min_child_samples[np.argmin(loss)])   

    learning_rate=[0.0001,0.001,0.01,0.1,0.2,0.5]  
    for n in learning_rate:
        xgb_c=XGBRegressor(n_iterators=1000,min_child_samples=min_child_samples[np.argmin(loss)],learning_rate=n)
        xgb_c.fit(X_train_c,y_train_c)
        y_pred=pred(xgb_c,X_val_c)
        if ((y_val_c >= 0).all() and (y_pred >= 0).all()):
            loss1.append(mean_squared_log_error(y_pred,y_val_c))
        #print('learning_rate:',n,'msle:',mean_squared_log_error(y_pred,y_val_c))
    print('Best learning_rate:',learning_rate[np.argmin(loss1)])   

    num_leaves=[5,10,30,50,100]
    for n in num_leaves:
        xgb_c=XGBRegressor(n_iterators=1000,min_child_samples=min_child_samples[np.argmin(loss)],learning_rate=learning_rate[np.argmin(loss1)]
                                ,num_leaves=n)
        xgb_c.fit(X_train_c,y_train_c)
        y_pred=pred(xgb_c,X_val_c)
        if ((y_val_c >= 0).all() and (y_pred >= 0).all()):
            loss2.append(mean_squared_log_error(y_pred,y_val_c))
        #print('num_leaves:',n,'msle:',mean_squared_log_error(y_pred,y_val_c))
    print('Best lnum_leaves:',num_leaves[np.argmin(loss2)])  

    reg_alpha=[0.0,0.01,0.05,0.1,0.5]
    for n in reg_alpha:
        xgb_c=XGBRegressor(n_iterators=1000,min_child_samples=min_child_samples[np.argmin(loss)],learning_rate=learning_rate[np.argmin(loss1)]
                      ,reg_alpha=n,num_leaves=num_leaves[np.argmin(loss2)])
        xgb_c.fit(X_train_c,y_train_c)
        y_pred=pred(xgb_c,X_val_c)
        if ((y_val_c >= 0).all() and (y_pred >= 0).all()):
            loss3.append(mean_squared_log_error(y_pred,y_val_c))
        #print('reg_alpha:',n,'msle:',mean_squared_log_error(y_pred,y_val_c))
    print('Best reg_alpha:',reg_alpha[np.argmin(loss3)]) 

    n_estimators=[50,100,200,500,1000]
    for n in n_estimators:
        xgb_c=XGBRegressor(n_iterators=1000,min_child_samples=min_child_samples[np.argmin(loss)],learning_rate=learning_rate[np.argmin(loss1)]
                      ,reg_alpha=reg_alpha[np.argmin(loss3)],num_leaves=num_leaves[np.argmin(loss2)],n_estimators=n)
        xgb_c.fit(X_train_c,y_train_c)
        y_pred=pred(xgb_c,X_val_c)
        if ((y_val_c >= 0).all() and (y_pred >= 0).all()):
            loss4.append(mean_squared_log_error(y_pred,y_val_c))
        #print('n_estimators:',n,'msle:',mean_squared_log_error(y_pred,y_val_c))
    print('Best n_estimators:',n_estimators[np.argmin(loss4)])   
    xgb_c=XGBRegressor(n_iterators=1000,min_child_samples=min_child_samples[np.argmin(loss)],learning_rate=learning_rate[np.argmin(loss1)]
                      ,reg_alpha=reg_alpha[np.argmin(loss3)],num_leaves=num_leaves[np.argmin(loss2)],n_estimators=n_estimators[np.argmin(loss4)])
    xgb_c.fit(X_train_c,y_train_c)
    return xgb_c

参数优化

参数优化主要针对XGBoost,采用网格搜索(GridSearchCV)找到最优参数。GridSearchCV即网格搜索和交叉验证。它是一种调参手段,通过穷举搜索,在所有候选的参数选择中,通过循环遍历,尝试每一种可能性,表现最好的参数就是最终的结果。它的搜索结果非常耗时。

class sklearn.model_selection.GridSearchCV(estimator, param_grid, scoring=None,
fit_params=None, n_jobs=None, iid=’warn’, refit=True, cv=’warn’, verbose=0,
pre_dispatch=2*n_jobs’, error_score=raise-deprecating’, return_train_score=’warn’)
  1. estimator:选择使用的分类器,并且传入除需要确定最佳的参数之外的其他参数。每一个分类器都需要一个scoring参数,或者score方法:如estimator = RandomForestClassifier(min_sample_split=100,min_samples_leaf = 20,max_depth = 8,max_features = ‘sqrt’ , random_state =10),
  2. param_grid:需要最优化的参数的取值,值为字典或者列表,例如:param_grid = param_test1,param_test1 = {‘n_estimators’ : range(10,71,10)}
  3. scoring = None :模型评价标准,默认为None,这时需要使用score函数;或者如scoring = ‘roc_auc’,根据所选模型不同,评价准则不同,字符串(函数名),或是可调用对象,需要其函数签名,形如:scorer(estimator,X,y);如果是None,则使用estimator的误差估计函数。
  4. fit_para,s = None
  5. n_jobs = 1 : n_jobs:并行数,int:个数,-1:跟CPU核数一致,1:默认值
  6. iid = True:iid:默认为True,为True时,默认为各个样本fold概率分布一致,误差估计为所有样本之和,而非各个fold的平均。
  7. refit = True :默认为True,程序将会以交叉验证训练集得到的最佳参数,重新对所有可能的训练集与开发集进行,作为最终用于性能评估的最佳模型参数。即在搜索参数结束后,用最佳参数结果再次fit一遍全部数据集。
  8. cv = None:交叉验证参数,默认None,使用三折交叉验证。指定fold数量,默认为3,也可以是yield训练/测试数据的生成器。
  9. verbose = 0 ,scoring = None  verbose:日志冗长度,int:冗长度,0:不输出训练过程,1:偶尔输出,>1:对每个子模型都输出。
  10. pre_dispatch = ‘2*n_jobs’ :指定总共发的并行任务数,当n_jobs大于1时候,数据将在每个运行点进行复制,这可能导致OOM,而设置pre_dispatch参数,则可以预先划分总共的job数量,使数据最多被复制pre_dispatch次。

对xgboost进行调参:

import xgboost as xgb
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import roc_auc_score

需要调整的参数

parameters = {
              'max_depth': [10, 15, 20, 25],
              'objective':['reg:linear'],
              'learning_rate': [0.01, 0.02, 0.05, 0.1],
              'n_estimators': [500, 1000, 2000],
              'min_child_weight': [0, 2, 5],
              'subsample': [0.6, 0.7, 0.8, 0.85, 0.95],
              'reg_alpha': [0, 0.25, 0.5, 0.75, 1],
              'reg_lambda': [0.2, 0.4, 0.6, 0.8, 1],
              'scale_pos_weight': [0.2, 0.4, 0.6, 0.8, 1]
}
xlf = xgb.XGBRegressor(params)

gs = GridSearchCV(xlf, param_grid=parameters, scoring='accuracy', cv=3)
gs.fit(X_train, y_train)

print("Best score: %0.3f" % gs.best_score_)
print("Best parameters set: %s" % gs.best_params_ )
  • 4
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值