stumpClassify()函数是通过阈值比较对数据进行分类的,有4个参数值。所有的阈值一边的数据都会分到类别-1,另外一边的数据分到类别+1。该函数通过数组过滤来实现,首先将返回数组的第一维数据的长度值(也就是行数)设置为1,然后将所有满足不等式要求的设置为-1,不等式可以任意切换。该函数用于测试是否有某个值小于或者大于我们正在测试的阈值。
现在让我们来看看如何在实践中快速的应用该类方法。上节内容介绍的是简单的函数程序,这次我们直接采用现有的包解决实际问题。
本节内容中采用scikit- learn包提供的所有包。首先导入所有需要的库(本节运行在linux的notebooks)。
准备数据
在本节所有的例子中,我们将讨论二分类问题作为测试。生成20维人工数据集,包含1000个样本,其中8个特征包含信息,3个冗余,2个重复。
然后我们采用split将数据分割成训练/测试部分,这对于所有方法的验证是有必要的。
在深入研究算法之前,让我们执行一个目标变量分布的检查以确保数据的完整性。
(1)我们首先采用决策树方法来进行预测,首先创建一个决策树。使用训练数据进行学习,并使用测试样本对结果进行评估。
我们可以看到两个明显的结果:
1、Loss值有些偏高(因为决策树的叶子输出为0或1,这在预测错误时会有严重的惩罚。但是accuracy分数相当不错,)
我们来检查一下前几个预测的输出,可以看到5个分类中只有2个实例被正确分类。
(2)我们采用Adaboost来对该实例进行预测,我们创建一个运行在1000次迭代上的AdaBoost分类器(创建1000棵树)。我们采用最流行的单层决策树(也被称为decision stump),跟上节用的一样,每颗树根据单一特征来进行分类。我们也将使用SAMME算法来处理离散数据(base_estimator的输出为0或1)。
Loss值远低于单一决策树(主要是因为我们获得的是概率输出)。精度是相同的,但是注意到树的结构要简单得多。因为我们创建了1000个单层决策树。
此外,我们还可以快速查看一下预测值,在5个实例的测试中有4个是正确分类的。
顺便来查看一下第一棵树图。
在最后的计算中,该树的错误值和重要值(即决策树权重向量D中的权值)如下,该树的重要性比较高:
(3)我们采用GBT方法来计算一次,我们构建一个1000棵树组成的一个梯度提升树,这1000棵树中每棵连续的树都是通过梯度优化来创建的。同样,我们将把大多数参数留给它们的默认值,只指定树的最大深度为1(同样为单层决策树),并为更智能的计算设置warm_start = True。
得到的结果显然是所提出的算法中最优的。我们已经得到了最精确的算法,给出了关于分类概率的更合理的预测。
不同的是,GBC(Gradient Boosting Classifier)使用的是以均值-平方误差作为标准值的决策树分类器。这个结果与树的输出略有不同——现在叶子包含的是一个预测值。
Xgboost近几年比较火,在Kaggle比赛中结构化数据(简单来说就是数据库。结构化数据也称作行数据,是由二维表结构来逻辑表达和实现的数据,严格地遵循数据格式与长度规范,主要通过关系型数据库进行存储和管理。与结构化数据相对的是不适于由数据库二维表来表现的非结构化数据,包括所有格式的办公文档、XML、HTML、各类报表、图片和咅频、视频信息等。)的竞赛项目中取得了非凡的成绩,在机器学习领域取得的成绩要远超过其余机器学习的方法(SVM、logistic regression. etc)
在以决策树为基函数的Boosting方法为BoostingTree方法,此类方法的大多数树包的问题是,他们不会非常重视正规化问题-他们允许生成许多非常相似的树木,该类树有时还会很茂密,这都会导致过拟合问题。
而在GBT中则尝试加入一些正则化参数的方法这个问题。我们可以:
控制树结构(最大深度,每叶的最小样本),
控制学习率,
通过引入随机性降低方差(stochastic gradient boosting-使用随机的实例和特征样本)等方法。
而我们可以通过使用XGBoosting更加进一步改善正规化问题。
损失函数取决于正在执行的任务(分类,回归等),正则化项如下方程:
第一部分是负责控制创建叶片的总数,第二部分监视每一个叶片的分数。算法通过使用梯度下降法来进行优化目标,这也产生了如何寻找一个最佳结构的连续树的问题。
(1)标准接口实践
我们首先要下载相应的库文件numpy和xgboost。
加载数据。我们将使用捆绑的Agaricus数据集,下载地址:
https://github.com/dmlc/xgboost/tree/master/demo/data。
这个数据集记录了不同蘑菇种类的生物属性,目标是预测它是否有毒。这个数据集包括了在Agaricus和Lepiota家族中有23种蘑菇的假设样本的描述。每个物种都被认定为绝对食用,绝对有毒,或不为人知,不推荐。后者与有毒的一种结合在一起。该指南明确指出,没有简单的规则来确定蘑菇的可食性;它由8124个实例组成,具有22个属性(数字和分类)。目标分类要么是0,要么是1,这意味着是一个二分类问题。
重要提示:XGBoost只处理数字变量。
所有的数据都已经为我们准备好了。分类变量已经被编码,所有的实例被分成训练和测试数据集。数据需要存储在DMatrix对象中,用于处理稀疏数据集。它可以用一下几种方式填充:
使用libsvm格式txt文件,
使用Numpy 2D数组(最流行),
使用XGBoost二进制缓冲文件
在这种情况下,我们将使用第一种选择。
Libsvm文件只存储格式中的非零元素,任何缺失的特征都表明它的对应值为0。如下表示:
我们查看一下数据集情况
训练数据集包含6513行和127列
测试数据集包含1611行和127列
训练labels如下所示,为二分类问题。
我们设定好训练参数,让我们假设算法参数如下:
为了训练分类器,我们简单地传递给它一个训练数据集,参数列表和关于迭代次数的信息。
我们还可以使用watchlist观察测试数据集的性能
作出预测
通过简单的准确率计算以验证结果。当然,正常过程我们应该对数据的验证集执行验证,但在这种情况下,准确性是足够的。
(2)使用Scikit-learn接口
需要下载如下所需要的库
使用数据集,和(1)使用的相同的数据集。
scikit- learn包提供了一个方便的函数load_svmlight,可以同时读取许多libsvm文件,并将它们存储为Scipy的稀疏矩阵。
检查load的数据集
指定训练参数,所有的参数跟前面的示例相同设置:
开始训练分类器
开始预测
计算error值
两种不同接口的Xgboost方法介绍完毕,接下来章节将介绍更深入的学习过程。
1、本节内容主要介绍如何区分数据集中的特性的相对重要性。我们可以找出是什么驱动了树的分割,以及我们可以在特性工程上做出的一些改进。
装载相关库xgboost、seaborn、pandas
装载数据,和上节所用的数据集相同
我们指定训练参数-使用5个单层决策树以及平均学习率。
开始训练模型,我们同样采用watchlist查看测试性能
在构建树的过程中被多次地划分(我们的例子中只有一次)—这个操作称为split。为了完成split,算法必须计算出哪个是最好的特征然后去使用。
在那之后,在我们的底部,我们得到树叶的观察。
在最终的模型中,这些树叶对于每棵树来说应该尽可能的纯净,每一个叶子都应该由一个标签类组成。
并不是所有的split都同样重要。基本上,树的第一个split会对纯度产生更大的影响。直观上,我们理解第一个split做了大部分工作,接下来的split集中在数据集被第一棵树错误地分类的那一部分,这部分工作比较少。
同样,在Boosting中,我们试图优化每一轮的错误分类(它被称为损失)。所以第一棵树将会做大的工作,下面的树将会集中在剩下的工作上,这部分工作在之前的树上没有正确的学习。
每一次split操作带来的提升都可以衡量,这就是收获。
-引用自Kaggle 陈天奇的Kaggle notebook。
让我们来研究一下树的样子:
对于每一个split,我们得到以下细节:
1、这个特征被用来split,
2、可能的选择去生成(分支)
3、gain是通过特征得到的真实提升值。之前的想法是,在特征X上添加一个新的split到有一些有错误分类的分支上,通过增加split到这个特征后,将会有两个新的分支,这些每一个分支都会更准确。
4、cover测量与该特征相关的观测的相对数量
可视化
希望有更好的方法来弄清楚哪些特征才是真正重要的。我们可以使用内置函数plot_importance,它将创建一个根据标准而呈现最重要特性的绘图。我们将分析每个特征对所有splits和所有树的影响,并可视化结果。
查看哪些特征提供了最多的增益:
我们可以通过引入f–score使得结果更显而易见。F-score表示了每个特征上执行的split的次数。
偏差(bias error)和方差(varianceerror)的权衡
接下来我们展示如何处理偏差/方差权衡的可视化,这是常见的机器学习问题。
分类器有两种常见的误差——偏差和方差误差。
偏差是是预测值(估计值)的期望与真实值之间的差异程度,偏差越大,越偏离真实数据。
方差是是预测值的变化范围,离散程度,也就是离其期望值的距离,方差越大,数据的分布越分散。
我们所期望的状态是两个错误都尽可能低。从 ScottFortmann-Roe's blog 的博客上的图形可以很好地将这个问题可视化。假设目标的中心是完美的模型。我们重复我们的实验,重创建模型并在相同的数据点上使用它。
欠拟合和过拟合
了解了偏差和方差引入的错误,我们可以着手处理这些与训练模型有关的问题。我们将使用从scikit-学习文档中获取的图来帮助我们可视化那些欠拟合和过拟合的问题。
2、为了量化描述的效果,我们将训练模型几次,以选择不同的参数值。让我们考虑一下,我们想要找到一个最优的树数——我们不希望模型非常简单,但目前我们也不想让模型过于复杂。
我们将会:
生成复杂的二分类数据集,
使用Scikit-learn包,
使用10次交叉循环验证对树的不同值进行建模(n_estimators)训练
绘图训练/测试误差
从加载所需的库开始,设置随机的种子数
然后生成人工数据集
我们将分为10折交叉验证 (相同的标签平均分布在每个交叉集中)进行测试
让我们来看看树的数量如何影响预测的准确性:
显示验证曲线图:
看看这个图,我们可以得出以下结论:
在增加新树的同时,训练分数也在不断增加,但从某种程度上来说,交叉验证的分数是固定的
方差是最低的,低于25棵树的偏差很高,
从大约25棵树中,方差越来越大,而交叉验证值偏倚保持稳定(没有必要增加额外的树/复杂度)
我们可以看到,模型在增加复杂度时保持了稳定的方差
我们可以假设在n_estimators = 50中实现模型的稳定。但是模型的方差仍然很大。
我们可以通过那些方式来进行优化这些问题呢?
(1)处理高方差
如果模型太过于复杂,我们可以尝试:
用更少的功能(即,特征选择),
使用更多的训练样本(即,人工生成的),
增加规则化(增加惩罚对额外的复杂性)
在XGBoost中,我们可以尝试:
降低每棵树的深度(max_depth),
增加min_child_weight参数,
增加γ(gamma)参数,
使用subsample,colsample_bytree参数添加更多的随机性,
增加lambda和alpha正则化参数
(2)处理高偏差
如果模型太简单的话:
添加更多的功能(即,更好的功能工程),
更复杂的模型
减少正规化
在XGBoost中,你可以这样做:
增加每棵树的深度(max_depth),
减少min_child_weight参数,
减少γ参数,
减少lambda和alpha正则化参数
让我们稍微调整一下参数。我们将增加一些随机性——我们将使用70%随机选择的样本和60%随机选择的特征。这应该有助于减少方差。为了减少偏差(更大的准确性),尝试为每棵树增加一个额外的等级。
我们得到了一个更小的方差模型,偏差也有所减小。
3、超参数调优
我们学习机器学习的都知道,模型优化,调参都是一门技巧活(好多时候也是瞎蒙凭感觉),有很多的可调参数。每一个参数都有可能导致不同的输出。问题是哪种组合结果最好呢。
下面的notebook将向您展示如何使用Scikit-learn模块为您的模型找出最佳的参数。
首先import 相关库
寻找最佳参数是一个迭代过程。我们应该从粗粒度的开始进行优化,然后转向更详细的参数进行优化。
(2)随机网格搜索
当参数的数量和它们的值越来越大时,传统的网格搜索方法很快就变得无效了。一个可能的解决方案可能是随机从它们的分布中选取某些参数。虽然这不是一个完美的解决方案,但值得一试。
创建一个参数分布字典:
初始化RandomizedSearchCV,随机选取10个参数组合。通过这种方法,我们可以轻松地控制已测试模型的数量。
生成分类器
再次看一下选择的参数和它们的准确性分数:
最佳的评估器、参数值和得分
4.结果评估
在本节notebook中,我们将学习如何度量算法的性能。
开始准备相关的库文件
加载agaricus数据集:
设置训练参数——我们将使用平均学习率的5个决策树。
在训练这个模型之前,我们还可以指定watchlist数组来观察它在两个数据集上的性能。
使用预定义的评估指标
哪些指标是直接可用的呢?
已经有一些预定义的评估标准。您可以在训练模型时使用它们作为eval_metric参数的输入。
rmse -均方根误差,
mae-平均绝对误差,
logloss——负对数损失函数
error-二分类错误率。它采用(错误的情况)/(所有情况)来计算的。
merror -多类分类错误率。计算的方式为(错误的情况)/ (所有情况),
auc –曲线下面积
ncg -归一化的贴现累计收益,
map-平均平均精度
默认情况下将使用error度量。
如果需要修改评估标准的话,只需将eval_metric参数指定到params字典。
当然也可以同时使用多个评估标准
创建自定义评价标准值
为了创建我们自己的评估指标,唯一需要做的是创建一个方法,采用两个参数——预测概率和DMatrix对象持有的数据。
在下面的实例中,我们的分类度量将简单地计算错误分类示例的数量,默认的概率p>0.5的类是积极性的。如果我们想要的概率值作为阈值,那就可以改变这个参数。
当错误分类的例子越来越少的时候,算法就会变得越来越好。记住在训练时也要设置参数maximize= False。
我们可以发现,即使params字典持有eval_metric的key值,这些值也被feval忽略和覆盖。
提取评价结果
我们可以通过声明保存值的字典,并将其作为eval_result参数的参数传递来获得评估分数。
我们可以重新用这么参数来进行后续操作,比如print、plot等
早期停止
在选择合适的树数量时,有一个很好的优化技巧。
我们可以训练该模型直到某个验证分数时停止继续优化。验证时需要减少每个early_stopping_rounds来继续训练。这种方法的结果更简单,因为树的最低数量将被找到(简单性)。
在下面的实例中,将创建总数为1500棵树,但是如果验证分数在最近的10次迭代中没有改善,我们就告诉它停止。
当使用early_stopping_rounds参数时,模型将会产生有3个额外的字段- bst.best_score,bst。best_iteration bst.best_ntree_limit。
交叉验证结果
自带的包提供了一个用于交叉验证结果的选项(但不像Sklearn包那样复杂)。下一个输入将显示基本的执行方法。注意,我们只传递一个DMatrix参数,而我们可以将训练集和测试集合并到一个对象中,以获得更多的训练样本将是有利的。
注意:
默认情况下,我们得到一个pandas数据帧对象(可以用as_pandas参数来改变),
通过作为参数传递指标(允许使用多值),
我们可以使用自己的评估指标(参数中的feval和maximize),
我们可以使用早期停止特性(参数early_stopping_rounds)
5、处理缺失值
下面的notebook展示了XGBoost对缺失值的处理。两种方法——原包接口和Sklearn包针对缺少的数据集进行测试。
缺失值经常在真实的数据集中出现。处理丢失值上,没有规则能够适用于所有的情况,因为缺少值的原因有很多种。
首先import所有的库
让我们准备一个没有缺失值的有效数据集。有10个样本,每一个样本将包含5个随机生成的特征,每个样本根据5个特征划进行二分类问题。
我们增加一些缺失值
生成目标变量,随机生成0/1的目标label
(1)原包接口
在本例中,我们将检查原包接口如何处理丢失的数据。从专门的默认参数开始。
在第一个实例中,我们将创建一个有效的DMatrix(带有所有值),看看它是否可行,然后再重复这个过程。
交叉验证结果
输出显然没有任何意义,因为数据完全是随机的。
当创建DMatrix时,我们必须明确表示它丢失了什么。有时可能是0,999或者是其他。在我们的例子中是Numpy 格式下的NAN来表示的。增加missing参数为DMatrix构造函数来处理它。
然后进行交叉验证
虽然因为随机的数据导致这个结果跟之前一样,但是这个方法是适用于缺失值处理的。
在XGBoost包中,选择的是软方法来处理缺失值。
当使用带有缺失值的特性来进行拆分时,XGBoost将为缺失值分配一个方向,而不是数值。
具体地说,XGBoost将所有的带有缺失值的数据点分别指向左方和右方,然后在关系到目标时选择更高增益的方向。
(2)Sklearn包
下面的部分展示了如何使用Sklearn接口验证相同的内容。
首先定义参数并创建一个估计对象。
用完整的数据集交叉验证结果。因为我们只有10个样品,所以我们只需要做2折的交叉验证。
我们得到了一些分数,我们不会深入研究它的解释。
看看目标是否也有缺失的值
这两种方法都适用于缺少的数据集。缺失情况下,Sklearn包处理带有np.nan作为缺失数据。(如果使用不同的缺失值标记,就需要额外的预处理)。
6、处理不平衡数据集
处理不平衡数据集
在现实世界的问题中,有很多例子处理不平衡的目标类别。想象一下医疗数据,在成千上万个阴性(正常)的例子中,只有少数阳性的例子。另一个例子可能是分析欺诈交易,在这种交易中,实际的欺诈只占所有可用数据的一小部分。
不平衡数据指的是分类问题,其中的类不是均匀分布的。
一般建议:
当接近不平衡的数据集时,这些都是常用的策略:
收集更多的数据,
使用更好的评估指标(error、AUC、F1、Kappa,…)
尝试过抽样少数类别或低抽样多数类别,
生成少数群体的人工样本(SMOTE算法)
在XGBoost中,我们可以尝试如下方法:
确保参数min_child_weight很小(因为叶节点可以有较小的大小组),默认设置为min_child_weight = 1,
对DMatrix进行调整时为特定的样本分配更多的权重,
使用set_pos_weight参数控制正负权重的平衡,
使用AUC评价
实践部分,首先装载必要的库
我们将使用一个函数来生成二进制分类的数据集。为了保证它不平衡使用权重参数。在这种情况下,将会有200个样本,每个样本有5个特征,但只有10%(大约20个样本)是阳性的。这让问题变得更加棘手。
将创建的数据划分为训练集和测试集。记住,这两个数据集在分布上都应该是相似的。
基准模型
在这种方法中,试着完全忽略分类是不平衡的事实,看看它是如何执行的。为训练和测试数据创建DMatrix。
假设我们将创建15个单层决策树,解决二分类问题,每个决策树将会非常积极地进行训练。
这些参数也将在连续的例子中使用。
训练booster并做出预测
生成结果
我们还可以使用3个不同的评估指标来展示模型:
自定义权重
让我们指定正例样本有5x的权重,并在创建DMatrix时添加这些信息。
训练分类器并进行预测
生成结果
我们在这里做了一个指标上的权衡。我们现在可以更好地对少数群体进行分类,但整体的准确性和精度却降低了。我们可以测试多种权重组合,看看哪个最有效。
使用scale_pos_weight参数
我们可以通过计算负性和正例之间的比例,并将其设置为scale_pos_weight参数,来实现手动分配权重的过程。
初始化数据集
计算两个类之间的比率,并将其赋值给一个参数。
生成结果
我们可以看到,在本例中使用scale_pos_weight参数手动来增减权重,这样做的效果更好。我们现在可以完美地分类所有的posivie类(这也是我们需要做的真正的问题)。另一方面,分类器有时会错误地将负面情况分类为正(产生所谓的假阳性)。