1. 引入
1.1 决策树
为达到目标根据一定的条件进行选择的过程,就是决策树,决策树模型非常经典,在机器学习中常被用于分类,构成它的元素是节点和边,节点会根据样本的特征做出判断,最初的分支点被称为根节点,其余成为子节点,没有分支的点是叶子节点,代表分类结果。
决策树的衡量标准是熵。在热力学中,熵被用来描述一个系统内在的混乱程度;在决策树中,熵代表是分支下样本种类的丰富性,样本种类越多越混乱,熵就越大。如果分支下的样本完全属于同一类,熵就为0。构造树的基本思路就是随着树是深度也就是层数的增加,让熵快速降低,熵降低的速度越快,代表决策树分类效率越高。
优点:是天然可解释性,苹果之所以是好苹果,是因为它又大又红又甜、
缺点:容易过拟合。解决方法很简单:去掉一些分支,剪枝有两种:预剪枝是在训练开始前规定条件,比如树达到某一深度就停止训练;后剪枝则是先找到树,再依据一定条件如限制叶子结点的个数,去掉一部分分支。
1.2 随机森林
森林里有许多数,随机森林里有很多决策树,随机森林是决策树的升级版,随机指的是树的生长过程,世界上没有两片相同的树叶,随机森林中的树也各不相同。
在构建决策树时,我们会从训练数据中有放回的随机选取一部分样本,也不会使用数据的全部特征,而是随机选取部分特征进行训练,每棵树使用的样本和特征各不相同,训练的结果也自然不同。为什么这么做?在训练的最初,我们并不知道哪些是异常样本,也不知道哪些特征对分类结果影响更大,随机的过程降低了两者对分类结果的影响。随机森林的输出结果由投票决定,如果大部分决策树认为测试结果是好苹果,我们就认为他是好苹果。
由于树与树之间的独立,他们可以同时训练,不需要花费太长时间,随机的过程让它不容易过拟合,能处理特征较多的高维数据,也不需要做特征选择,合理训练后准确性很高,不知道用什么分类方法时,先试试随机森林准没错。
在机器学习中,随机森林属于集成学习,也就是将多个模型组合起来解决问题,这些模型会独立学习、预测、再投票出结果,准确度往往比单独的模型高很多。除了决策树,还可以使用神经网络等其他模型,同样的,集成学习内部不必是同样的模型,神经网络和决策树可以共存于一个系统中。
1.3 GBDT(Gradient Boosting Decision Tree)梯度提升决策树
GBDT在搜索、广告、推荐系统等领域有广泛应用,能处理标签、数值等各类数据,解释性强。由于树与树之间的相互依赖,需要较长的训练时间。
运用多个模型共同解决问题,GBDT自然属于集成学习。
在集成学习中,一个模型依赖于上一个模型,共同逼近正确答案的方法(如GBDT)被称为Boosting提升;模型间相互独立共同投票出结果的方法(如随机森林),则被称为Bagging装袋;还有一种Stacking堆叠,是在多个模型的基础上放置一个更高层的模型,将底层模型的输出作为它的输入,由它给出最终的预测结果。
1.4 XGBoost(eXtreme Gradient Boosting)极端梯度提升
XGBoost是GBDT的优秀版本,是一种基于决策树的集成机器学习算法,使用梯度上升框架,适用于分类和回归问题。
XGBoost的整体结构与GBDT一致,都是在训练出一棵树的基础上,再训练下一棵树,预测它与真实分布间的差距,通过不断训练用来弥补差距的树,最终使用树的组合实现对称式分布。
优点:
①它的目标函数包括损失函数和正则项部分。损失函数代表模型拟合数据的程度,我们通常使用一阶导数指出其梯度下降的方向,XGBoost还计算了它的二阶导数,进一步考虑了梯度变化的趋势,收敛更快、精度更高;正则项用来控制模型的复杂程度,叶子节点越多,模型越大,运行时间越长,超过一定限度后模型过拟合会导致精度下降,XGBoost的正则项是一个惩罚机制,叶子节点的数目越多,惩罚力度越大,从而限制他们的数量。
②加快了计算速度。树的构建中,最耗时的部分是为确定最佳分裂点而进行的特征值排序,XGBoost在训练前会先将特征进行排序,存储为Block结构,可以实现并行处理,此后重复使用此结构来减少计算量。
③善于捕捉复杂数据间的依赖关系,能从大规模数据中获取有效模型,在实用性上支持多种系统语言。XGBoost 允许⽤户定义⾃定义优化⽬标和评价标准它对模型增加了⼀个全新的维度,所以我们的处理不会受到任何限制,有着高度的灵活性。
④缺失值处理
XGBoost内置处理缺失值的规则。⽤户需要提供⼀个和其它样本不同的值,然后把它作为⼀个参数传进去,以此来作为缺失值的取值。XGBoost在不同节点遇到缺失值时采⽤不同的处理⽅法,并且会学习未来遇到缺失值时的处理⽅法。
⑤内置交叉验证
XGBoost允许在每⼀轮boosting迭代中使⽤交叉验证。因此,可以⽅便地获得最优boosting迭代次数。⽽GBM使⽤⽹格搜索,只能检测有限个值。
缺点:在高维稀疏特征数据集和小规模数据集上表现不是很好。
代码实现
决策树分类:
import pandas as pd
# from sklearn.inspection import permutation_importance
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.ensemble import RandomForestClassifier
from xgboost.sklearn import XGBClassifier
# 处理数据 找出目标值和特征值X, y
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state= 22)
dec = DecisionTreeClassifier()
gbc = GradientBoostingClassifier()
rfc = RandomForestClassifier()
xgbc = XGBClassifier()
dec.fit(X_train,y_train)
rfc.fit(X_train,y_train)
gbc.fit(X_train,y_train)
xgbc.fit(X_train,y_train)
y_pred = dec.predict(X_test)) # 预测测试集
# print("训练集准确率:%s"%clas.score(X_train,y_train)) #输出训练集准确度
print("DecisionTreeClassifier准确率为:",dec.score(X_test,y_test))
print("RandomForestClassifier准确率为:",rfc.score(X_test,y_test))
print("GradientBoostingClassifier准确率为:",gbc.score(X_test,y_test))
print(metrics.classification_report(y_test, y_pred) # 输出结果,精确度、召回率、f-1分数
print(metrics.confusion_matrix(y_test, y_pred)) # 混淆矩阵
决策树回归:
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score,mean_squared_error
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.ensemble import GradientBoostingRegressor
from xgboost import XGBRegressor
# 处理数据 找出目标值和特征值X, y
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.22, random_state= 22)
dtr = DecisionTreeRegressor( criterion='mse', random_state=22)
rfr = RandomForestRegressor(n_estimators=1000, criterion='mse', random_state=22, n_jobs=-1)
gbr = GradientBoostingRegressor(n_estimators=1000, criterion='mse', random_state=22)
xgbr = GradientBoostingRegressor(n_estimators=1000, criterion='mse', random_state=22)
rfr.fit(X_train, y_train)
y_train_pred = rfr.predict(X_train)
y_test_pred = rfr.predict(X_test)
print('MSE train: %.3f, test: %.3f' % (mean_squared_error(y_train, y_train_pred), mean_squared_error(y_test, y_test_pred)))
print('R^2 train: %.3f, test: %.3f' % (r2_score(y_train, y_train_pred), r2_score(y_test, y_test_pred)))
特征重要度:
# 特征重要性
from xgboost import plot_importance
from matplotlib import pyplot as plt
plot_importance(model)
plt.show()
2. XGBoost vs GBDT
2.1 比较
• 性质:GBDT是机器学习算法,XGBoost除了算法内容还包括一些工程实现方面的优化。
• 基于二阶导:GBDT使用的是损失函数一阶导数,相当于函数空间中的梯度下降;而XGBoost还使用了损失函数二阶导数,相当于函数空间中的牛顿法。
• 正则化:XGBoost显式地加入了正则项来控制模型的复杂度,能有效防止过拟合。
• 列采样:XGBoost采用了随机森林中的做法,每次节点分裂前进行列随机采样。
• 缺失值处理:XGBoost运用稀疏感知策略处理缺失值,而GBDT没有设计缺失策略。
• 并行高效:XGBoost的列块设计能有效支持并行运算,提高效率。
2.2 优点
• 算法本身的优化:首先GBDT只支持决策树,Xgboost除了支持决策树,可以支持多种弱学习器,可以是默认的gbtree, 也就是CART决策树,还可以是线性弱学习器gblinear以及DART;其次GBDT损失函数化简的时候进行的是一阶泰勒公式的展开,而Xgboost使用的是二阶泰勒公式的展示。还有一点是Xgboost的目标函数加上了正则项,这个正则项是对树复杂度的控制,防止过拟合。
• 可以处理缺失值。尝试通过枚举所有缺失值在当前节点是进入左子树,还是进入右子树更优来决定一个处理缺失值默认的方向
• 运行效率:并行化,单个弱学习器最耗时的就是决策树的分裂过程,对于不同特征的特征分裂点,可以使用多线程并行选择。这里想提一下,我自己理解,这里应该针对的是每个节点,而不是每个弱学习器。这里其实我当时深究了一下,有点混乱。为什么是针对每个节点呢?因为我每个节点也有很多特征,所以在每个节点上,我并行(多线程)除了多个特征,每个线程都在做寻找增益最大的分割点。还有需要注意的一点是Xgboost在并行处理之前,会提前把样本按照特征大小排好序,默认都放在右子树,然后递归的从小到大拿出一个个的样本放到左子树,然后计算对基于此时的分割点的增益的大小,然后记录并更新最大的增益分割点
参考:https://blog.csdn.net/weixin_45928096/article/details/124848415