Gradient Boosting是一种Boosting的方法 , 它的主要思想是每一次建立模型是在之前建立模型损失函数的梯度下降方向。损失函数式评价模型性能(一般为拟合程度+正则项) , 认为损失函数越小 , 性能越好 。而让损失函数持续下降 , 就能使得模型不断提升性能 , 其最好的方法就是使损失函数沿着梯度方向下降。
Gradient Boosting Decision Tree每一次建立树模型是在之前建立损失函数的梯度下降方向。 即利用了损失函数的负梯度在当前模型的值作为回归问题提升树算法的残差近似值 , 去拟合一棵回归树。
具体算法算理:GBDT原理-Gradient Boosting Decision Tree
为什么基分类器选用决策树 ? ===>决策树可以认为是if-then规则的集合 , 易于理解 , 可解释性强 , 预测速度快。同时 , 决策树算法相比于其他的算法需要更少的特征工程 , 比如可以不用做特征标准化 , 可以很好的处理字段缺失的数据 , 也可以不用关心特征间是否相互依赖等。决策树能够自动组合多个特征 , 它可以毫无压力地处理特征间的交互关系并且是非参数化的 , 因此不必担心异常值或者数据是否线性可分。不过 , 单独使用决策树算法时 , 有容易过拟合缺点。 所幸的是 , 通过各种方法 , 抑制决策树的复杂性 , 降低单棵决策树的拟合能力 , 再通过梯度提升的方法集成多个决策树 , 最终能够很好的解决过拟合的问题。
由此可见 , 梯度提升方法和决策树学习算法可以互相取长补短, 是一对完美的搭档。至于抑制单棵决策树的复杂度的方法有很多 , 比如限制树的最大深度、限制叶子节点的最少样本数量、限制节点分裂时的最少样本数量、吸收Bagging的思想对驯良样本采样(subsample) , 在学习单棵决策树时只使用一部分训练样本、借鉴森林的思路在学习单棵决策树时只采样一部分特征 、在目标函数中添加正则项惩罚复杂的树结构等。
GBDT二分类采用的损失函数是对数损失 : 因为损失函数是将所有样本的损失函数加起来 , 面对对数损失函数便是将和转变为乘的 , 故采用对数损失函数。
GBDT分类 : 每一棵树拟合当前整个模型的损失函数的负梯度 , 构建新的树加到当前模型中形成新模型 , 下一棵树拟合新模型的损失函数的负梯度。
from sklearn import ensemble
clf = ensemble.GradientBoostingClassifier()
gbdt_model = clf.fit(X_train,y_trian) # Traning model
pred_x = gbdt_model.predict_proba(test1217_x)[:,1] # predict : probably of 1
# 包含的参数
# loss = loss(损失函数), learning_rate = learning_rate(学习率), n_estimators = n_estimators(迭代次数),
# min_samples_split = min_samples_split(最小样本切分),
# min_samples_leaf = min_samples_leaf(最小叶子节点数),
# min_weight_fraction_leaf = min_weight_fraction_leaf(最小叶子节点切分权重),
# max_depth = max_depth(最大深度), init = init, subsample = subsample,
# max_features = max_features(最大特征数),
# random_state = random_state(随机切分比例), verbose = verbose,
# max_leaf_nodes = max_leaf_nodes, warm_start = warm_start,
# presort = presort
GBDT回归 : 每一棵树拟合当前模型的残差 , 构建新的树加到当前模型中形成新模型 , 下一棵树拟合新模型的损失函数的负梯度。
from sklearn import ensemble
clf = ensemble.GradientBoostingRegressor()
gbdt_model = clf.fit(X_train,y_train) # Training model
y_upper = gbdt_model.predict(x_test) # predict
# 包含的参数和上面一致
GBDT调参问题 : sklearn中GBDT调参
GBDT运用的正则化技巧 , 防止模型过于复杂 , 参考文章GBDT运用的正则化技巧
特征决定模型性能上界 , 例如深度学习方法也是将数据如何更好的表达为特征。如果能够将数据表达成为线性可分的数据 , 那么使用简单的线性模型就可以取得很好的效果。GBDT构建新的特征也是使特征更好地表达数据。
**主要思想 *GBDT每棵树的路径直接作为LR输入特征使用。
用已有特征训练GBDT模型,然后利用GBDT模型学习到的树来构造新特征,最后把这些新特征加入原有特征一起训练模型。构造的新特征向量是取值0/1的,向量的每个元素对应于GBDT模型中树的叶子结点。当一个样本点通过某棵树最终落在这棵树的一个叶子结点上,那么在新特征向量中这个叶子结点对应的元素值为1,而这棵树的其他叶子结点对应的元素值为0。新特征向量的长度等于GBDT模型里所有树包含的叶子结点数之和。
上图为混合模型结构。输入特征通过增强的决策树进行转换。每个单独树的输出被视为稀疏性分类器的分类输入特征。增强的决策树被证明是非常强大的特征转换。
例子1 : 上图有两棵树 , 左树有三个叶子节点 , 右树有两个叶子节点 , 最终的特征即为五维的向量。对于输入x , 假设他落在左树的第一个节点 , 编码[1,0,0] , 落在右树第二个节点则编码[0,1] , 所以整体的编码为[1,0,0,0,1] , 这类编码作为特征, 输入到线性分类模型(LR or FM)中进行分类。
从另外一篇博客中我的理解是 : 这里两棵树给的是同一个样本 , 只是对样本进行了不同的划分 , 比如:样本为[3.4,5.6,7.8] , 我们得知该样本类别为点击(记为01) , 则我们可将样本写为[3.4,5.6,7.8,0]和[3.4,5.6,7.8,1]分别进入两棵树 , 继而得到最终的编码.针对样本有三类的情况 , 我们实质上是在每轮的训练的时候是同时训练三棵树。假设这个样本属于第二类 , 第一棵树针对样本x的第一类 , 输入为(x,0)。第二颗树针对样本x的第二类 , 输入为(x,1)。第三棵树针对样本x的第三类 , 输入为(x,0)
在这里每棵树的训练过程其实就是我们之前已经提到过的Cart Tree的生成过程。在此处我们参照之前的生成树程序 , 就可以解出三棵树以及三棵树对x类别的预测值f1(x) , f2(x) , f3(x) 。那么在此类训练中 , 我们仿照多分类的逻辑回归 , 使用softmax(映射函数)来产生概率 , 则属于类别1的概率是并且我们可以针对类别1求出残差y11(x) = 0-p1(x) ; 类别2求出残差y22(x) = 1-p2(x) ; 类别3求出残差y33(x) = 0-p3(x) .
然后开始第二轮针对第一类输入为(x,y11(x)) , 针对第二类输入为(x,y22(x)) , 针对第三类输入为(x,y33(x)) , 继续训练出第三棵树 , 一直迭代M轮 , 每轮构建3棵树。
所以当K=3 , 我们其实应该有三个式子(Cim表示预测值的均值 = 1/N*sum(yi) , I属于Rim就为1 , 不属于为0)当训练完毕以后 , 新来一个样本x1 , 我们需要预测该样本的类别的时候 , 便可以有这三个产生三个值 , f1(x) , f2(x) , f3(x) 。样本属于某个类别c的概率为
在CTR预估中 , 如何利用AD ID是一个问题。
直接将AD ID作为特征建树不可行 , 而onehot编码过于稀疏 , 为每一个AD ID建GBDT树 , 相当于发掘出区分每个广告的特征。而对于曝光不充分的样本即长尾部分 , 无法单独建树。
综合方案为 : 使用GBDT对非ID和ID分别建一类树。
例子2: 下图假设训练了3棵深度为2的树模型 , 对于输入X , 在第一棵树属于节点4 , 第二棵树属于节点7,第三棵树属于节点6 , 所以生成的特征为 : "1:4 2:7 3:6"
FFM详细资料>>
libFFM适用于例子2的情况 , 即只用使用每棵树的index
LR适用于例子1的情况 , 须将节点使用one-hot编码
# 弱分类器的数目
n_estimator = 10
# 随机生成分类数据。
X, y = make_classification(n_samples=80000)
# 切分为测试集和训练集,比例0.5
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5)
# 将训练集切分为两部分,一部分用于训练GBDT模型,另一部分输入到训练好的GBDT模型生成GBDT特征,然后作为LR的特征。这样分成两部分是为了防止过拟合。
X_train, X_train_lr, y_train, y_train_lr = train_test_split(X_train, y_train, test_size=0.5)
# 调用GBDT分类模型。
grd = GradientBoostingClassifier(n_estimators=n_estimator)
# 调用one-hot编码。
grd_enc = OneHotEncoder()
# 调用LR分类模型。
grd_lm = LogisticRegression()
'''使用X_train训练GBDT模型,后面用此模型构造特征'''
grd.fit(X_train, y_train)
# fit one-hot编码器
grd_enc.fit(grd.apply(X_train)[:, :, 0])
'''
使用训练好的GBDT模型构建特征,然后将特征经过one-hot编码作为新的特征输入到LR模型训练。
'''
grd_lm.fit(grd_enc.transform(grd.apply(X_train_lr)[:, :, 0]), y_train_lr)
# 用训练好的LR模型多X_test做预测
y_pred_grd_lm = grd_lm.predict_proba(grd_enc.transform(grd.apply(X_test)[:, :, 0]))[:, 1]
# 根据预测结果输出
fpr_grd_lm, tpr_grd_lm, _ = roc_curve(y_test, y_pred_grd_lm)
对于样本量大的数据 , 线性模型具有训练速度快的特点 , 但线性模型学习能力限于线性可分数据 , 所以就需要特征工程将数据尽可能地从输入空间转换到线性可分的特征空间。GBDT与LR的融合模型 , 其实使用GBDT来发掘有区分度的特征以及组合特征 , 来替代人工组合特征。工业中GBDT+LR、GBDT+FM都是应用比较广泛。
参考文档 : http://blog.csdn.net/shine19930820/article/details/71713680
GBDT和随机森林都是基于决策树而得到的。决策树比较不易受到离群点和缺失值的影响。决策树不考虑空间分布 , 也不考虑分类器的结构 吗是一种无参算法。但是决策树比较容易过拟合 , 另外 , 决策树不易处理连续型变量。
RF是Bagging算法的优化版本 , 改进一 : 基学习器限定为决策树 , 改进二 : 除了bagging在样本上加上扰动 , 同时属性上也加上了扰动 , 即在决策树学习的过程中引入了随机属性选择 , 即不止有样本的随机选择还有属性的随机选择。
RF的起始性能较差 , 特别当只有一个基学习器时 , 随着学习器数目增多 , 随机森林通常会收敛到更低的泛化误差。随机森林的训练效率也会高于Bagging , 因为单个决策树在构建中 , Bagging使用的是’确定性’决策树 , 在选择特征划分结点时 , 要对所有的特征进行考虑 , 而随机森林使用的是’随机性’特征数 , 只需要考虑特征的子集。
**优点 : ** 训练可以高度并行化
, 对于大数据时代的大样本训练速度有优势 ; 能够处理高维的数据 , 并且不用特征选择 , 而且在训练完后 , 给出特征的重要性 ; 相对于Boosting系列的Adaboost和GBDT , RF实现比较简单。
**缺点 : **在噪声较大的分类或者回归问题上容易过拟合。
**ET的原理 : **算法与随机算法十分相似 , 都是由许多决策树构成。但是与随机森林有两点主要的区别 :
当特征属性是类别的形式时,随机选择具有某些类别的样本为左分支,而把具有其他类别的样本作为右分支;当特征属性是数值的形式时,随机选择一个处于该特征属性的最大值和最小值之间的任意数,当样本的该特征属性值大于该值时,作为左分支,当小于该值时,作为右分支。这样就实现了在该特征属性下把样本随机分配到两个分支上的目的。然后计算此时的分叉值(如果特征属性是类别的形式,可以应用基尼指数;如果特征属性是数值的形式,可以应用均方误差)。遍历节点内的所有特征属性,按上述方法得到所有特征属性的分叉值,我们选择分叉值最大的那种形式实现对该节点的分叉。
由于随机选择了特征值的划分点位 , 而不是最优点位 , 这样会导致生成的决策树的规模一般会大于RF所生成的决策树。也就是说 , **模型的方差相对于RF进一步减少 , **但是偏差相对于RF进一步增大。在某些时候 , extra trees的泛化能力比RF更好。
GBDT是集成学习Boosting家族的成员,是对提升树的改进。提升树是加法模型、学习算法为前向分布算法时的算法。不过它限定基本学习器为决策树。对于二分类问题,损失函数为指数函数,就是把AdaBoost算法中的基本学习器限定为二叉决策树就可以了;对于回归问题,损失函数为平方误差,此时,拟合的是当前模型的残差。梯度提升树GBDT是对提升树算法的改进,提升树算法只适合误差函数为指数函数和平方误差,对于一般的损失函数,梯度提升树算法利用损失函数的负梯度在当前模型的值,作为残差的近似值。
**GBDT建树关键点 : **采用ensemble决策树而非单棵树 ; 建树采用GBDT而非RF
GBDT与传统Boosting区别较大 , 它的每一次计算都是为了减少上一次的残差 , 而为了消除残差 , 我们可以在残差减小的梯度方向上建立模型 , 所以说 , 在GradienBoost中 , 每个新的模型的建立是为了使得之前的模型的残差往残差梯度下降的方向 , 与传统的Boosting中关注正确错误样本的加权有着很大的区别。
**优点 : **它能灵活的处理各种类型的数据 ; 在相对较少的调参时间下 , 预测的准确度较高 , 相对于SVM来说的。
**缺点 : **基学习器之间存在串行关系 , 难以并行训练数据。
XGBoost是Boosting算法的其中一种 , Boosting算法的思想是将许多弱分类器集成在一起 , 形成一个强分类器。因为XGBoost是一种提升树模型 , 所以它是将许多书模型集成在一起 , 形成一个很强的分类器。XGBoost是极端梯度提升树 , 其基本思想 : 一棵树一棵树逐渐地往模型里面加 , 每加一棵Cart决策树时 , 要使得整体的效果(目标函数有所下降)有所提升。使用多棵决策树(多个单一的弱分类器)构成组合分类器 , 并且给每个叶子节点赋予一定的权值。
XGBoost算法可以给预测模型带来能力的提升。
XGBoost可以自动学习出它的分裂方向。
XGBoost内置处理缺失值的规则。用户需要提供一个和其他样本不同的值 , 然后把它作为一个参数传进去 , 以此来作为缺失值的取值。XGBoost在不同节点遇到缺失值时采用不同的处理方法 , 并且会学习未来遇到缺失值时的处理方法。1,点击此处,下载对应自己Python版本的网址。
2 , 输入安装代码 : pip install xgboost-0.81-cp37-cp37m-win_amd64.whl
XGBoost目标函数 = 训练误差 + 正则化惩罚项 ===> Obj(θ) = L(θ) + Ω(θ)
XGBoost也是拟合的在数据上的残差,但是它是用泰勒展式对模型损失残差的近似;同时XGBoost对模型的损失函数进行的改进,并加入了模型复杂度的正则项。
Boosting的最大好处在于,每一步的残差计算其实变相地增大了分错instance的权重,而已经分对的instance则都趋向于0。这样后面的树就能越来越专注那些前面被分错的instance。
XGBoost可以加载多种数据格式的训练数据 :
libsvm 格式的文本数据 ;
Numpy 的二维数组 ;
XGBoost 的二进制的缓存文件。加载的数据存储对象在DMatrix中。
加载libsvm格式的数据 : dtrain1 = xgb.DMatrix('train.svm.txt')
加载二进制的缓存文件 : dtrain2 = xgb.DMatrix('train.svm.buffer')
加载numpy的数组 :
data = np.random.rand(5,10) # 5改行10列数据集
label = np.random.randint(2,size=5) # 二分类目标值
dtrain = xgb.DMatrix(data, label = label) # 组成训练集
将scipy.sparse格式的数据转化为DMatrix格式
dtrain = xgb.DMatrix('train.svm.txt')
dtrain.save_binary("train.buffer")
可以使用如下方式处理DMatrix中的缺失值dtrain = xgb.DMatrix(data , label=label , missing=-999.0)
当需要给样本设置权重时 , 可以用如下方式 :
w = np.random.rand(5,1)
dtrain = xgb.DMatrix(data,label = label,missing=-999.0,weight=w)
XGBoost使用key-value字典的方式存储参数
在运行XGBoost之前 , 必须设置三种类型参数 : general parameters,booster parameters和task parameters
**通用参数(General Parameters) : **该参数控制在提升(boosting)过程中使用哪种booster,常用的booster有树模型(tree)和线性模型(linear model)
Booster参数(Booster Parameters):这取决于使用哪种booster
学习目标参数(Task Parameters):控制学习的场景,例如在回归问题中会使用不同的参数控制排序
# xgboost模型
params = {
##### 2.1通用参数
'booster':'gbtree', # 有两种模型可以选择gbtree和gblinear。gbtree使用基于树的模型进行提升计算 , gblinear使用线性模型进行提升计算。缺省(默认)值为gbtree
'silent':0, # 设置成1 则没有运行信息输入,最好是设置成0 ; 默认为0
'nthread':7, #CPU线程数 , 默认值为当前系统可以获得的最大线程数
# verbosity:[默认 =1] 打印消息的详细程度,有效值为0(静默),1(警告),2(信息),3(调试)。有时,XGBoost会尝试根据启发式更改配置,启动式显示为警告消息。如果出现意外,请尝试增加详细程度。
# num_pbuffer : 预测缓冲区大小 , 通常设置为训练实例的数目。缓冲用于保存最后一步提升的预测结果 , 无需人为设置。
# num_feature : Boosting过程中用到的特征维数 , 设置为特征个数 , XGBoost会自动设置 , 无需人为设置
# disable_default_eval_metric :[默认 = 0] 标记以禁止默认度量标准,设置为> 0 以禁止。
##### 2.2 tree booster参数
'eta':0.007, # 如同学习率 , 为了防止过拟合 , 更新过程中用到的收缩步长。在每次提升计算之后 , 算法会直接获得新特征的权重。eta通过缩减特征的权重式计算过程更加保守。默认值为0.3 , 取值范围:[0,1] , 典型值为:0.01-0.2
'gamma':0.1, # 用于控制是否后剪枝的参数,越大越保守,一般0.1 0.2的样子。在节点分裂时 , 只有分裂后损失函数的值下降了 , 才会分裂这个节点。Gamma指定了节点分裂所需的最小损失函数下降值。这个参数值越大 , 算法越保守。取值范围为:[0,∞)
'max_depth':12, # 构建树的深度,越大越容易过拟合。默认值为6 , 取值范围为 :[0,∞) , 要使用CV函数来进行调优。典型值:3-10
# max_delta_step [default=0] :我们允许每个树的权重被估计的值。如果它的值被设置为0,意味着没有约束;如果它被设置为一个正值,它能够使得更新的步骤更加保守。通常这个参数是没有必要的,但是如果在逻辑回归中类极其不平衡这时候他有可能会起到帮助作用。把它范围设置为1-10之间也许能控制更新。 取值范围为:[0,∞)
# min_child_weight [default=1] :孩子节点中最小的样本权重和。如果一个叶子节点的样本权重和小于min_child_weight则拆分过程结束。在现行回归模型中,这个参数是指建立每个模型所需要的最小样本数。这个参数用于避免过拟合。当它的值较大时,可以避免模型学习到局部的特殊样本。但是如果这个值过高,会导致欠拟合。这个参数需要使用CV来调整。取值范围为:[0,∞]
'subsample':0.7, # 随机采样训练样本 , 用于训练模型的子样本占整个样本集合的比例。取值范围是:(0,1] ,默认为1
'colsample_bytree':3,# 这个参数默认为1,是每个叶子里面h的和至少是多少
# 对于正负样本不均衡时的0-1分类而言,假设h在0.01附近,min_child_weight为1
#意味着叶子节点中最少需要包含100个样本。这个参数非常影响结果,
# 控制叶子节点中二阶导的和的最小值,该参数值越小,越容易过拟合
# colsample_bytree , colsample_bylevel , colsample_bynode [默认 =1] 这是对列的子采样参数家族,所有的colsample_by* 参数的范围均为(0,1),默认值为1.
# colsample_bytree [default=1] :在建立树时对特征采样的比例。缺省值为1 。取值范围为:(0,1]
# colsample_bylevel :是每个级别的列的子采样率,对于树中达到的每个新深度级别,子采样都会发生一次,列是从当前树的列集中进行子采样的。
# colsample_bynode:是每个节点(拆分)的列的子采样率。每次评估新的拆分时,都会发生一次子采样。列是从为当前级别选择的列集中进行二次采样的。
# colsample_by* :参数累积起作用。例如,与64个功能的组合将在每个拆分中留下4个功能可供选择。
{'colsample_bytree':0.5, 'colsample_bylevel':0.5, 'colsample_bynode':0.5}
##### 2.3 Linear Booster参数
'lambda':2, # 控制模型复杂度的权重值的L2 正则化项参数,参数越大,模型越不容易过拟合 , 默认值1
# 'alpha'[default = 1]:L1正则的惩罚系数,增加此值可以使模型更加保守
# lambda_bias:在偏置上的L2正则。缺省(默认)值为0(在L1上没有偏置项的正则,因为L1偏置时不需要)
##### 2.4 学习目标参数
'objective':'multi:softmax', # 多分类问题
# objective[default = reg:linear] :定义学习任务及相应的学习目标,可选择的目标函数如下:
# "reg:linear" —— 线性回归。
# "reg:logistic"—— 逻辑回归。
# "binary:logistic"—— 二分类的逻辑回归问题,输出为概率。
# "binary:logitraw"—— 二分类的逻辑回归问题,输出的结果为wTx。
# "count:poisson"—— 计数问题的poisson回归,输出结果为poisson分布。在poisson回归中,max_delta_step的缺省值为0.7。(used to safeguard optimization)
# "multi:softmax" –让XGBoost采用softmax目标函数处理多分类问题,同时需要设置参数num_class(类别个数)
# "multi:softprob" –和softmax一样,但是输出的是ndata * nclass的向量,可以将该向量reshape成ndata行nclass列的矩阵。没行数据表示样本所属于每个类别的概率。
# "rank:pairwise" –set XGBoost to do ranking task by minimizing the pairwise loss
# base_score[default = 0.5]: 所有实例的初始化预测分数,全局偏置;当有足够的迭代次数时,改变这个值将不会有太大的影响
'seed':1000,# 随机数的种子 , 默认为0
#'eval_metric':'auc' 校验数据所需要的评价指标,不同的目标函数将会有缺省的评价指标(rmse for regression and error for classification mean average precision for ranking)
'num_class':10, # 类别数,与multi softmax并用
}
# 3 基本方法和默认参数
# xgboost.train(params,dtrain,num_boost_round=10,evals(),obj=None,feval=None,maximize=False,early_stopping_rounds=None,evals_result=None,verbose_eval=True,learning_rates=None,xgb_model=None)
# parms:这是一个字典,里面包含着训练中的参数关键字和对应的值,形式是parms = {'booster':'gbtree','eta':0.1}
# dtrain:训练的数据
# num_boost_round:这是指提升迭代的个数
# evals:这是一个列表,用于对训练过程中进行评估列表中的元素。形式是evals = [(dtrain,'train'),(dval,'val')] 或者是 evals =[(dtrain,'train')] ,对于第一种情况,它使得我们可以在训练过程中观察验证集的效果。
# obj :自定义目的函数
# feval:自定义评估函数
# maximize:是否对评估函数进行最大化
# early_stopping_rounds:早期停止次数,假设为100,验证集的误差迭代到一定程度在100次内不能再继续降低,就停止迭代。这要求evals里至少有一个元素,如果有多个,按照最后一个去执行。返回的是最后的迭代次数(不是最好的)。如果early_stopping_rounds存在,则模型会生成三个属性,bst.best_score ,bst.best_iteration和bst.best_ntree_limit
# evals_result:字典,存储在watchlist中的元素的评估结果
# verbose_eval(可以输入布尔型或者数值型):也要求evals里至少有一个元素,如果为True,则对evals中元素的评估结果会输出在结果中;如果输入数字,假设为5,则每隔5个迭代输出一次。
# learning_rates:每一次提升的学习率的列表
# xgb_model:在训练之前用于加载的xgb_model
#### 4 模型训练
num_round = 10
bst = xgb.train( plst, dtrain, num_round, evallist )
#### 5 模型预测
# X_test类型可以是二维List,也可以是numpy的数组
dtest = DMatrix(X_test)
ans = model.predict(dtest)
#### 6 保存模型
bst.save_model('test.model')
# 6.1 导出模型和特征映射(Map)
# 6.2 导出模型到文件
bst.dump_model('dump.raw.txt')
# 6.3 导出模型和特征映射
bst.dump_model('dump.raw.txt','featmap.txt')
#### 7 加载模型
bst = xgb.Booster({'nthread':4})#init model
bst.load_model("model.bin") # load data
Xgboost有两大类接口:Xgboost原生接口 和sklearn接口,并且Xgboost能够实现分类回归两种任务。下面对这四种情况做以解析。
from sklearn.datasets import load_iris
import xgboost as xgb
from xgboost import plot_importance
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score # 准确率
# 记载样本数据集
iris = load_iris()
X,y = iris.data,iris.target
# 数据集分割
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=123457)
# 算法参数
params = {
'booster':'gbtree',
'objective':'multi:softmax',
'num_class':3,
'gamma':0.1,
'max_depth':6,
'lambda':2,
'subsample':0.7,
'colsample_bytree':0.7,
'min_child_weight':3,
'slient':1,
'eta':0.1,
'seed':1000,
'nthread':4,
}
plst = params.items()
# 生成数据集格式
dtrain = xgb.DMatrix(X_train,y_train)
num_rounds = 500
# xgboost模型训练
model = xgb.train(plst,dtrain,num_rounds)
# 对测试集进行预测
dtest = xgb.DMatrix(X_test)
y_pred = model.predict(dtest)
# 计算准确率
accuracy = accuracy_score(y_test,y_pred)
print('accuarcy:%.2f%%'%(accuracy*100))
# 显示重要特征
plot_importance(model)
plt.show()
# 输出预测正确率以及特征重要性:
# accuarcy:93.33%
import xgboost as xgb
from xgboost import plot_importance
from matplotlib import pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_boston
from sklearn.metrics import mean_squared_error
# 加载数据集,此数据集时做回归的
boston = load_boston()
X,y = boston.data,boston.target
# Xgboost训练过程
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=0)
# 算法参数
params = {
'booster':'gbtree',
'objective':'reg:gamma',
'gamma':0.1,
'max_depth':5,
'lambda':3,
'subsample':0.7,
'colsample_bytree':0.7,
'min_child_weight':3,
'slient':1,
'eta':0.1,
'seed':1000,
'nthread':4,
}
dtrain = xgb.DMatrix(X_train,y_train)
num_rounds = 300
plst = params.items()
model = xgb.train(plst,dtrain,num_rounds)
# 对测试集进行预测
dtest = xgb.DMatrix(X_test)
ans = model.predict(dtest)
# 显示重要特征
plot_importance(model)
plt.show()
# 重要特征(值越大,说明该特征越重要
from xgboost.sklearn import XGBClassifier
clf = XGBClassifier(
silent=0, # 设置成1则没有运行信息输出,最好是设置为0,是否在运行升级时打印消息
# nthread = 4 # CPU 线程数 默认最大
learning_rate=0.3 , # 如同学习率
min_child_weight = 1,
# 这个参数默认为1,是每个叶子里面h的和至少是多少,对正负样本不均衡时的0-1分类而言
# 假设h在0.01附近,min_child_weight为1 意味着叶子节点中最少需要包含100个样本
# 这个参数非常影响结果,控制叶子节点中二阶导的和的最小值,该参数值越小,越容易过拟合
max_depth=6, # 构建树的深度,越大越容易过拟合
gamma = 0,# 树的叶子节点上做进一步分区所需的最小损失减少,越大越保守,一般0.1 0.2这样子
subsample=1, # 随机采样训练样本,训练实例的子采样比
max_delta_step=0, # 最大增量步长,我们允许每个树的权重估计
colsample_bytree=1, # 生成树时进行的列采样
reg_lambda=1, #控制模型复杂度的权重值的L2正则化项参数,参数越大,模型越不容易过拟合
# reg_alpha=0, # L1正则项参数
# scale_pos_weight =1 # 如果取值大于0的话,在类别样本不平衡的情况下有助于快速收敛,平衡正负权重
# objective = 'multi:softmax', # 多分类问题,指定学习任务和响应的学习目标
# num_class = 10, # 类别数,多分类与multisoftmax并用
n_estimators=100, # 树的个数
seed = 1000, # 随机种子
# eval_metric ='auc'
)
from sklearn.datasets import load_iris
import xgboost as xgb
from xgboost import plot_importance
from matplotlib import pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# 加载样本数据集
iris = load_iris()
X,y = iris.data,iris.target
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=12343)
# 训练模型
model = xgb.XGBClassifier(max_depth=5,learning_rate=0.1,n_estimators=160,silent=True,objective='multi:softmax')
model.fit(X_train,y_train)
# 对测试集进行预测
y_pred = model.predict(X_test)
#计算准确率
accuracy = accuracy_score(y_test,y_pred)
print('accuracy:%2.f%%'%(accuracy*100))
# 显示重要特征
plot_importance(model)
plt.show()
import xgboost as xgb
from xgboost import plot_importance
from matplotlib import pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_boston
# 导入数据集
boston = load_boston()
X ,y = boston.data,boston.target
# Xgboost训练过程
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=0)
model = xgb.XGBRegressor(max_depth=5,learning_rate=0.1,n_estimators=160,silent=True,objective='reg:gamma')
model.fit(X_train,y_train)
# 对测试集进行预测
ans = model.predict(X_test)
# 显示重要特征
plot_importance(model)
plt.show()
1,选择较高的学习速率(learning rate)。一般情况下,学习速率的值为0.1.但是,对于不同的问题,理想的学习速率有时候会在0.05~0.3之间波动。选择对应于此学习速率的理想决策树数量。Xgboost有一个很有用的函数“cv”,这个函数可以在每一次迭代中使用交叉验证,并返回理想的决策树数量。
2,对于给定的学习速率和决策树数量,进行决策树特定参数调优(max_depth , min_child_weight , gamma , subsample,colsample_bytree)在确定一棵树的过程中,我们可以选择不同的参数。
3,Xgboost的正则化参数的调优。(lambda , alpha)。这些参数可以降低模型的复杂度,从而提高模型的表现。
4,降低学习速率,确定理想参数。
下面详细的进行这些操作。
为了确定Boosting参数,我们要先给其他参数一个初始值。咱们先按照如下方法取值:
注意,上面这些参数的值知识一个初始的估计值,后继需要调优。这里把学习速率就设成默认的0.1。然后用Xgboost中的cv函数来确定最佳的决策树数量。
我们先对这两个参数调优,是因为他们对最终结果有很大的影响。首先,我们先大范围地粗略参数,然后再小范围的微调。
注意:在这一节我会进行高负荷的栅格搜索(grid search),这个过程大约需要15-30分钟甚至更久,具体取决于你系统的性能,你也可以根据自己系统的性能选择不同的值。
在已经调整好其他参数的基础上,我们可以进行gamma参数的调优了。Gamma参数取值范围很大,这里我们设置为5,其实你也可以取更精确的gamma值。
param_test3 = {
'gamma':[i/10.0 for i in range(0,5)]
}
gsearch3 = GridSearchCV(estimator = XGBClassifier( learning_rate =0.1,
n_estimators=140, max_depth=4,min_child_weight=6, gamma=0,
subsample=0.8, colsample_bytree=0.8,objective= 'binary:logistic',
nthread=4, scale_pos_weight=1,seed=27), param_grid = param_test3, scoring='roc_auc',n_jobs=4,iid=False, cv=5)
gsearch3.fit(train[predictors],train[target])
gsearch3.grid_scores_, gsearch3.best_params_, gsearch3.best_score_
尝试不同的subsample 和 colsample_bytree 参数。我们分两个阶段来进行这个步骤。这两个步骤都取0.6,0.7,0.8,0.9作为起始值。
由于gamma函数提供了一种更加有效的降低过拟合的方法,大部分人很少会用到这个参数,但是我们可以尝试用一下这个参数。
最后,我们使用较低的学习速率,以及使用更多的决策树,我们可以用Xgboost中CV函数来进行这一步工作。
总结一下,要想模型的表现有大幅的提升,调整每个参数带来的影响也必须清楚,仅仅靠着参数的调整和模型的小幅优化,想要让模型的表现有个大幅度提升是不可能的。要想模型的表现有质的飞跃,需要依靠其他的手段。诸如,特征工程(feature egineering) ,模型组合(ensemble of model),以及堆叠(stacking)等。
使用梯度提升算法的好处是在提升树被创建后,可以相对直接地得到每个属性的重要性得分。一般来说,重要性分数,衡量了特征在模型中的提升决策树构建中的价值。一个属性越多的被用来在模型中构建决策树,它的重要性就相对越高。
属性重要性是通过对数据集中的每个属性进行计算,并进行排序得到。在单个决策树中通过每个属性分裂点改进性能度量的量来计算属性重要性。由节点负责加权和记录次数,也就是说一个属性对分裂点改进性能度量越大(越靠近根节点),权值越大;被越多提升树所选择,属性越重要。性能度量可以是选择分裂节点的Gini纯度,也可以是其他度量函数。
最终将一个属性在所有提升树中的结果进行加权求和后然后平均,得到重要性得分。
一个已训练的Xgboost模型能够自动计算特征重要性,这些重要性得分可以通过成员变量feature_importances_得到。可以通过如下命令打印:
print(model.feature_importances_)
我们可以直接在条形图上绘制这些分数 , 以便获得数据集中每个特征的相对重要性的直观显示 , 例如 :
# plot
pyplot.bar(range(len(model.feature_importances_)),model.feature_importances_)
pyplot.show()
我们可以通过在the Pima Indians onset of diabetes 数据集上训练XGBoost模型来演示,并从计算的特征重要性中绘制条形图。
# plot feature importance manually
from numpy import loadtxt
from xgboost import XGBClassifier
from matplotlib import pyplot
from sklearn.datasets import load_iris
# load data
dataset = load_iris()
# split data into X and y
X = dataset.data
y = dataset.target
# fit model no training data
model = XGBClassifier()
model.fit(X, y)
# feature importance
print(model.feature_importances_)
# plot
pyplot.bar(range(len(model.feature_importances_)), model.feature_importances_)
pyplot.show()
运行这个实例 , 首先输出特征重要性分数以及相对重要性条形图
这种绘制的缺点在于 , 只显示了特征重要性而没有排序 , 可以在绘制之前对特征重要性得分进行排序。通过内建的绘制函数进行特征重要性得分排序后的绘制 , 这个函数就是plot_importance() , 示例如下 :
# plot feature importance manually
from numpy import loadtxt
from xgboost import XGBClassifier
from matplotlib import pyplot
from sklearn.datasets import load_iris
from xgboost import plot_importance
# load data
dataset = load_iris()
# split data into X and y
X = dataset.data
y = dataset.target
# fit model no training data
model = XGBClassifier()
model.fit(X, y)
# feature importance
print(model.feature_importances_)
# plot feature importance
plot_importance(model)
pyplot.show()
得到特征重要性的条形图并且是排序好的 , 根据其在输入数组的索引 , 特征自动命名为f0~f3 , 在问题描述中手动的将这些索引映射到名称 , 我们可以看到 , f2具有最高的重要性 , f1最低。
特征重要性得分,可以用于在scikit-learn中进行特征选择。通过SelectFromModel类实现,该类采用模型并将数据集转换为具有选定特征的子集。这个类可以采取预先训练的模型,例如在整个数据集上训练的模型。然后,它可以阈值来决定选择哪些特征。当在SelectFromModel实例上调用transform()方法时,该阈值被用于在训练集和测试集上一致性选择相同特征。
在下面的示例中,我们首先在训练集上训练xgboost模型,然后在测试上评估。使用从训练数据集计算的特征重要性,然后,将模型封装在一个SelectFromModel实例中。我们使用这个来选择训练集上的特征,用所选择的特征子集训练模型,然后在相同的特征方案下对测试集进行评估。
# select features using threshold
selection = SelectFromModel(model, threshold=thresh, prefit=True)
select_X_train = selection.transform(X_train)
# train model
selection_model = XGBClassifier()
selection_model.fit(select_X_train, y_train)
# eval model
select_X_test = selection.transform(X_test)
y_pred = selection_model.predict(select_X_test)
我们可以通过测试多个阈值,来从特征重要性中选择特征。具体而言,每个输入变量的特征重要性,本质上允许我们通过重要性来测试每个特征子集。
完整代码如下 :
# plot feature importance manually
import numpy as np
from xgboost import XGBClassifier
from matplotlib import pyplot
from sklearn.datasets import load_iris
from xgboost import plot_importance
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.feature_selection import SelectFromModel
# load data
dataset = load_iris()
# split data into X and y
X = dataset.data
y = dataset.target
# 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()
model.fit(X_train, y_train)
# feature importance
print(model.feature_importances_)
# make predictions for test data and evaluate
y_pred = model.predict(X_test)
predictions = [round(value) for value in y_pred]
accuracy = accuracy_score(y_test,predictions)
print("Accuracy:%.2f%%"%(accuracy*100.0))
#fit model using each importance as a threshold
thresholds = np.sort(model.feature_importances_)
for thresh in thresholds:
# select features using threshold
selection = SelectFromModel(model,threshold=thresh,prefit=True )
select_X_train = selection.transform(X_train)
# train model
selection_model = XGBClassifier()
selection_model.fit(select_X_train, y_train)
# eval model
select_X_test = selection.transform(X_test)
y_pred = selection_model.predict(select_X_test)
predictions = [round(value) for value in y_pred]
accuracy = accuracy_score(y_test,predictions)
print("Thresh=%.3f, n=%d, Accuracy: %.2f%%" % (thresh, select_X_train.shape[1], accuracy * 100.0))
# 结果如下 :
# [0.20993228 0.09029345 0.54176074 0.15801354]
# Accuracy:92.00%
# Thresh=0.090, n=4, Accuracy: 92.00%
# Thresh=0.158, n=3, Accuracy: 92.00%
# Thresh=0.210, n=2, Accuracy: 86.00%
# Thresh=0.542, n=1, Accuracy: 90.00%
我们可以看到,模型的性能通常随着所选择的特征的数量减少,在这一问题上,可以对测试集准确率和模型复杂度做一个权衡,例如选择三个特征,接受准确率为92%,这可能是对这样一个小数据集的清洗,但是对于更大的数据集和使用交叉验证作为模型评估方案可能是更有用的策略。
参考文献:
https://blog.csdn.net/waitingzby/article/details/81610495
https://blog.csdn.net/u011089523/article/details/72812019
https://blog.csdn.net/luanpeng825485697/article/details/79907149
https://xgboost.readthedocs.io/en/latest/parameter.html#general-parameters
原文地址https://www.cnblogs.com/wj-1314/p/9402324.html
逻辑回归假设数据服从伯努利分布
,通过极大化似然函数
的方法,运用梯度下降
来求解参数,来达到将数据二分类
的目的。
LR是广义线性模型,与传统线性模型相比,LR使用了Logit变换将函数值映射到0~1区间[2],映射后的函数值就是CTR的预估值。LR这种线性模型很容易并行化,处理上亿条训练样本不是问题,但线性模型学习能力有限,需要大量特征工程预先分析出有效的特征、特征组合,从而去间接增强LR的非线性学习能力。
Regression问题的常规步骤为 :
当梯度下降到一定数值后 , 每次迭代的变化很小 , 这时可以设定一个阈值 , 只要变化小于该阈值 , 就停止迭代 , 而得到的结果也近似于最优解。
若损失函数的值不断变大 , 则有可能是步长速率a太大 , 导致算法不收敛 , 这时可适当调整a值
对于样本数量非常之多的情况 , 普通的批量梯度下降算法(BGD)会非常耗时 , 靠近极小值是收敛速度减慢 , 因为每次迭代都要遍历所有样本 , 这时可以选择随机梯度下降算法(SGD)
梯度下降需要把m个样本全部带入计算 , 迭代一次计算量为m*n^2 ; 随机梯度下降每次只使用一个样本 , 迭代一次计算量为n^2 , 当m很大时 , 随机梯度下降迭代一次的速度要远高于梯度下降 , 虽然不是每次迭代得到的损失函数都想着全局最优方向 , 但是**整体的方向都是向全局最优解的 , 最终的结果往往是在全局最优解附近 **。
数据拟合问题 :
在CTR预估中 , 如何使用ad_id是一个问题 :
直接将ad_id作为特征建树不可行 , 而one-hot编码过于稀疏 , 为每个ad_id建GBDT树 , 相当于发掘出区分每个广告的特征。而对于曝光不充分的样本即长尾分布 , 无法单独建树。
综合方案为 : 使用GBDT对非ID和ID分别建一类树。
对于样本量大的数据 , 线性模型具有训练速度快的特点 , 但线性模型学习能力限于线性可分数据 , 所以就需要特征工程将数据尽可能地从输入空间转换到线性可分的特征空间。GBDT与LR的融合模型 , 其实使用GBDT来发掘有区分度的特征以及组合特征 , 来替代人工组合特征。
融合代码实现 :
import numpy as np # 快速操作结构数组的工具
import matplotlib.pyplot as plt # 可视化绘制
from sklearn.linear_model import LinearRegression # 线性回归
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.ensemble import GradientBoostingClassifier,RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score,roc_curve,auc
from sklearn.preprocessing import OneHotEncoder
# 弱分类器的数目
n_estimator = 10
# 随机生成分类数据。
X, y = make_classification(n_samples=80000,n_features=20,n_classes=2)
# 切分为测试集和训练集,比例0.5
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5)
# 将训练集切分为两部分,一部分用于训练GBDT模型,另一部分输入到训练好的GBDT模型生成GBDT特征,然后作为LR的特征。这样分成两部分是为了防止过拟合。
X_train_gbdt, X_train_lr, y_train_gbdt, y_train_lr = train_test_split(X_train, y_train, test_size=0.5)
# 调用GBDT分类模型。
gbdt = GradientBoostingClassifier(n_estimators=n_estimator)
# 调用one-hot编码。
one_hot = OneHotEncoder()
# 调用LR分类模型。
lr = LogisticRegression()
'''使用X_train训练GBDT模型,后面用此模型构造特征'''
gbdt.fit(X_train_gbdt, y_train_gbdt)
X_leaf_index = gbdt.apply(X_train_gbdt)[:, :, 0] # apply返回每个样本在每科树中所属的叶子节点索引。行数为样本数,列数为树数目。值为在每个数的叶子索引
X_lr_leaf_index = gbdt.apply(X_train_lr)[:, :, 0] # apply返回每个样本在每科树中所属的叶子节点索引。行数为样本数,列数为树数目。值为在每个数的叶子索引
print('每个样本在每个树中所属的叶子索引\n',X_leaf_index)
# fit one-hot编码器
one_hot.fit(X_leaf_index) # 训练one-hot编码,就是识别每列有多少可取值
X_lr_one_hot = one_hot.transform(X_lr_leaf_index) # 将训练数据,通过gbdt树,形成的叶子节点(每个叶子代表了原始特征的一种组合)索引,编码成one0-hot特征。
# 编码后的每个特征代表原来的一批特征的组合。
'''
使用训练好的GBDT模型构建特征,然后将特征经过one-hot编码作为新的特征输入到LR模型训练。
'''
# 使用lr训练gbdt的特征组合
print('使用逻辑回归训练GBDT组合特征的结果')
lr.fit(X_lr_one_hot, y_train_lr)
# 用训练好的LR模型多X_test做预测
y_pred_grd_lm = lr.predict_proba(one_hot.transform(gbdt.apply(X_test)[:, :, 0]))[:, 1] # 获取测试集正样本的概率
# 根据预测结果输出
fpr, tpr, thresholds = roc_curve(y_test, y_pred_grd_lm) # 获取真正率和假正率以及门限
roc_auc = auc(fpr, tpr)
print('auc值为\n',roc_auc)
#画图,只需要plt.plot(fpr,tpr),变量roc_auc只是记录auc的值,通过auc()函数能计算出来
plt.plot(fpr, tpr, lw=1, label='area = %0.2f' % roc_auc)
plt.show()
# 使用lr直接训练原始数据
print('使用逻辑回归训练原始数据集的结果')
lr.fit(X_train_lr, y_train_lr)
# 用训练好的LR模型多X_test做预测
y_pred_grd_lm = lr.predict_proba(X_test)[:, 1] # 获取测试集正样本的概率
# 根据预测结果输出
fpr, tpr, thresholds = roc_curve(y_test, y_pred_grd_lm) # 获取真正率和假正率以及门限
roc_auc = auc(fpr, tpr)
print('auc值为\n',roc_auc)
#画图,只需要plt.plot(fpr,tpr),变量roc_auc只是记录auc的值,通过auc()函数能计算出来
plt.plot(fpr, tpr, lw=1, label='area = %0.2f' % roc_auc)
plt.show()
L1正则项的等值线是方形,方形与J0的等值线相交时,相交点为顶点的概率很大,w1或w2等于零的概率很大。所以使用L1正则项的解具有稀疏性
。
L2正则项的等值线是圆,圆与J0的等值线相交时,w1或w2等于零的概率很小。所以使用L2正则项的解不具有稀疏性。
L1和L2正则是比较常见和常用的正则化项,都可以达到防止过拟合
的效果。
方差 是 x自身的波动情况
协方差,是x1,x2两个的相关情况 ,若是 x1 = x2 ,那么协方差就是方差了