Machine Learning——sklearn系列(五)——集成学习

一、集成学习

多个小模型,通过最后的决策算法来决定最后的结果。

集成方法常分为两类:
(1)averging methods:平均法的原则是: 独立的构建几个学习器,然后平均他们的预测。通常,组合的学习器要比任何一个单个的学习器要好,因为它降低了方差。
其中的代表:bagging 方法,随即森林
(2)boosting methods:学习器依次构建(递进方法),试图降低组合的学习器的偏差。 其中的代表:AdaBoost,Gradient Tree Boosting。xgboost是GBRT的工程版。

二、bagging

2.1 基本描述

在集成算法中,bagging 方法会在原始训练集的随机子集上构建一类黑盒估计器的多个实例,然后把这些估计器的预测结果结合起来形成最终的预测结果。 该方法通过在构建模型的过程中引入随机性,来减少基估计器的方差(例如,决策树)。 在多数情况下,bagging 方法提供了一种非常简单的方式来对单一模型进行改进,而无需修改背后的算法。 因为 bagging 方法可以减小过拟合,所以通常在强分类器和复杂模型上使用时表现的很好(例如,完全决策树,fully developed decision trees),相比之下 boosting 方法则在弱模型上表现更好(例如,浅层决策树,shallow decision trees)。

bagging 方法有很多种,其主要区别在于随机抽取训练子集的方法不同:

如果抽取的数据集的随机子集是样例的随机子集,我们叫做 Pasting 。
如果样例抽取是有放回的,我们称为 Bagging 。
如果抽取的数据集的随机子集是特征的随机子集,我们叫做随机子空间 (Random Subspaces)。
最后,如果基估计器构建在对于样本和特征抽取的子集之上时,我们叫做随机补丁 (Random Patches) 。
在 scikit-learn 中,bagging 方法使用统一的 BaggingClassifier 元估计器(或者 BaggingRegressor ),输入的参数和随机子集抽取策略由用户指定。n_estimators控制几个模型,max_samples 和 max_features 控制着子集的大小(对于样例和特征), bootstrap 和 bootstrap_features 控制着样例和特征的抽取是有放回还是无放回的。 当使用样本子集时,通过设置 oob_score=True ,可以使用袋外(out-of-bag)样本来评估泛化精度。

2.2 最终的预测结果

对于分类任务使用简单投票法,即每个分类器一票进行投票(也可以进行概率平均)
对于回归任务,则采用简单平均获取最终结果,即取所有分类器的平均值

2.3 代码(基于KNN的Bagging算法)

# bagging.py
#
import numpy as np
from sklearn import ensemble, neighbors, datasets, preprocessing
from sklearn.model_selection import train_test_split

from sklearn.metrics import accuracy_score

np.random.RandomState(0)

# 加载数据
wine = datasets.load_wine()

# 划分训练集与测试集
x, y = wine.data, wine.target
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3)

# 数据预处理
scaler = preprocessing.StandardScaler().fit(x_train)
x_train = scaler.transform(x_train)
x_test = scaler.transform(x_test)

# 创建模型
clf = ensemble.BaggingClassifier(neighbors.KNeighborsClassifier(), n_estimators=10, max_samples=0.5, max_features=0.5)

# 模型拟合
clf.fit(x_train, y_train)

# 预测
y_pred = clf.predict(x_test)

# 评估
print(accuracy_score(y_test, y_pred))

关于参数和方法要注意的是:

  • 首先控制特征子采样与样本子采样是否采用,采用的话是否要注意控制比例(一般而言,不要采取较小的数值,太小的特征子采样和样本子采样都会造成子学习器的性能太差.一般而言特征选择越少,方差越大,这点可以与最后的实验方差偏差分解对比分析).
  • 其次控制Bagging中的随机数参数random_state固定,不然不同实验的结果将不一致,同时要注意的很多时候random_state对于测试误差的影响很大,因此加入你想要在某一个数据集上使用Bagging,那么建议多尝试几个不同的Random_state
  • oob_score = True 对性能有一定的提升(使用袋外样本进行泛化能力的评估,但是很多时候效果并不明显,或者看不出什么效果)
  • 其他参数一般默认即可

三、随机森林

随机森林是非常具有代表性的Bagging集成算法,它的所有基评估器都是决策树,分类树组成的森林就叫做随机森林分类器,回归树所集成的森林就叫做随机森林回归器。这一节主要讲解RandomForestClassifier,随机森林分类器。

3.1 重要参数

3.1.1 控制基评估器的参数

参数含义
criterion不纯度的衡量指标,有基尼系数和信息熵两种选择
max_depth树的大深度,超过大深度的树枝都会被剪掉
min_samples_leaf一个节点在分枝后的每个子节点都必须包含至少min_samples_leaf个训练样 本,否则分枝就不会发生
min_samples_split一个节点必须要包含至少min_samples_split个训练样本,这个节点才允许被分 枝,否则分枝就不会发生
max_featuresmax_features限制分枝时考虑的特征个数,超过限制个数的特征都会被舍弃, 默认值为总特征个数开平方取整
min_impurity_decrease限制信息增益的大小,信息增益小于设定数值的分枝不会发生

这些参数在随机森林中的含义,和我们在上决策 树时说明的内容一模一样,单个决策树的准确率越高,随机森林的准确率也会越高,因为装袋法是依赖于平均值或 者少数服从多数原则来决定集成的结果的。

3.1.2 n_estimators

这是森林中树木的数量,即基评估器的数量。这个参数对随机森林模型的精确性影响是单调的,n_estimators越 大,模型的效果往往越好。但是相应的,任何模型都有决策边界,n_estimators达到一定的程度之后,随机森林的 精确性往往不在上升或开始波动,并且,n_estimators越大,需要的计算量和内存也越大,训练的时间也会越来越 长。对于这个参数,我们是渴望在训练难度和模型效果之间取得平衡。

n_estimators的默认值在现有版本的sklearn中是10,但是在即将更新的0.22版本中,这个默认值会被修正为 100。这个修正显示出了使用者的调参倾向:要更大的n_estimators。

3.1.2.1 建立一片森林

树模型的优点是简单易懂,可视化之后的树人人都能够看懂,可惜随机森林是无法被可视化的。所以为了更加直观 地让大家体会随机森林的效果,我们来进行一个随机森林和单个决策树效益的对比。我们依然使用红酒数据集。

3.1.2.1.1 随机森林和单个决策树效益的对比

from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_wine

wine = load_wine()

# 实例化
# 训练集带入实例化的模型去进行训练,使用的接口是fit
# 使用其他接口将测试集导入我们训练好的模型,去获取我们希望过去的结果(score.Y_test)
from sklearn.model_selection import train_test_split

Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data, wine.target, test_size=0.3)

clf = DecisionTreeClassifier(random_state=0)
rfc = RandomForestClassifier(random_state=0)
clf = clf.fit(Xtrain, Ytrain)
rfc = rfc.fit(Xtrain, Ytrain)
score_c = clf.score(Xtest, Ytest)
score_r = rfc.score(Xtest, Ytest)

print("Single Tree:{}".format(score_c)
      , "Random Forest:{}".format(score_r)
      )
# Single Tree:0.8333333333333334 Random Forest:0.9259259259259259

3.1.2.1.2 画出随机森林和决策树在一组交叉验证下的效果对比

from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_wine

wine = load_wine()

# 实例化
# 训练集带入实例化的模型去进行训练,使用的接口是fit
# 使用其他接口将测试集导入我们训练好的模型,去获取我们希望过去的结果(score.Y_test)
from sklearn.model_selection import train_test_split

Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data, wine.target, test_size=0.3)

# 交叉验证:是数据集划分为n分,依次取每一份做测试集,每n-1份做训练集,多次训练模型以观测模型稳定性的方法

from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt

rfc = RandomForestClassifier(n_estimators=25)
rfc_s = cross_val_score(rfc, wine.data, wine.target, cv=10)

clf = DecisionTreeClassifier()
clf_s = cross_val_score(clf, wine.data, wine.target, cv=10)

plt.plot(range(1, 11), rfc_s, label="RandomForest")
plt.plot(range(1, 11), clf_s, label="Decision Tree")
plt.legend()
plt.show()

# ====================一种更加有趣也更简单的写法===================#

""" 
label = "RandomForest" 
for model in [RandomForestClassifier(n_estimators=25),DecisionTreeClassifier()]:
    score = cross_val_score(model,wine.data,wine.target,cv=10)    
    print("{}:".format(label)),print(score.mean())    
    plt.plot(range(1,11),score,label = label)    
    plt.legend()    
    label = "DecisionTree"

"""

在这里插入图片描述

3.1.2.1.3 画出随机森林和决策树在十组交叉验证下的效果对比

from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_wine

wine = load_wine()

# 实例化
# 训练集带入实例化的模型去进行训练,使用的接口是fit
# 使用其他接口将测试集导入我们训练好的模型,去获取我们希望过去的结果(score.Y_test)
from sklearn.model_selection import train_test_split

Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data, wine.target, test_size=0.3)

# 交叉验证:是数据集划分为n分,依次取每一份做测试集,每n-1份做训练集,多次训练模型以观测模型稳定性的方法

from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt

rfc_l = []
clf_l = []

for i in range(10):
    rfc = RandomForestClassifier(n_estimators=25)
    rfc_s = cross_val_score(rfc, wine.data, wine.target, cv=10).mean()
    rfc_l.append(rfc_s)
    clf = DecisionTreeClassifier()
    clf_s = cross_val_score(clf, wine.data, wine.target, cv=10).mean()
    clf_l.append(clf_s)

plt.plot(range(1, 11), rfc_l, label="Random Forest")
plt.plot(range(1, 11), clf_l, label="Decision Tree")
plt.legend()
plt.show()

# 是否有注意到,单个决策树的波动轨迹和随机森林一致?
# 再次验证了我们之前提到的,单个决策树的准确率越高,随机森林的准确率也会越高

在这里插入图片描述

3.1.2.1.4 n_estimators的学习曲线
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_wine

wine = load_wine()
Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data, wine.target, test_size=0.3)
superpa = []
for i in range(200):
    rfc = RandomForestClassifier(n_estimators=i + 1, n_jobs=-1)
    rfc_s = cross_val_score(rfc, wine.data, wine.target, cv=10).mean()
    superpa.append(rfc_s)
print(max(superpa), superpa.index(max(superpa)))
plt.figure(figsize=[20, 5])
plt.plot(range(1, 201), superpa)
plt.show()

在这里插入图片描述

3.1.3 random_state

随机森林的本质是一种装袋集成算法(bagging),装袋集成算法是对基评估器的预测结果进行平均或用多数表决 原则来决定集成评估器的结果。在刚才的红酒例子中,我们建立了25棵树,对任何一个样本而言,平均或多数表决 原则下,当且仅当有13棵以上的树判断错误的时候,随机森林才会判断错误。单独一棵决策树对红酒数据集的分类 准确率在0.85上下浮动,假设一棵树判断错误的可能性为0.2(ε),那20棵树以上都判断错误的可能性是:
在这里插入图片描述
其中,i是判断错误的次数,也是判错的树的数量,ε是一棵树判断错误的概率,(1−ε)是判断正确的概率,共判对 25-i次。采用组合,是因为25棵树中,有任意i棵都判断错误。

import numpy as np
from scipy.special import comb

print(np.array([comb(25, i) * (0.2 ** i) * ((1 - 0.2) ** (25 - i)) for i in range(13, 26)]).sum()# 0.00036904803455582827
)

3.2 代码

# 随机深林.py
#
import numpy as np
from sklearn import tree,ensemble, datasets, preprocessing
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import graphviz

np.random.RandomState(0)

# 加载数据
wine = datasets.load_wine()

# 划分训练集与测试集
x, y = wine.data, wine.target
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3)

# 数据预处理
scaler = preprocessing.StandardScaler().fit(x_train)
x_train = scaler.transform(x_train)
x_test = scaler.transform(x_test)

# 创建模型
clf = ensemble.RandomForestClassifier(n_estimators=25,max_depth=3)

# 模型拟合
clf.fit(x_train, y_train)

# 预测
y_pred = clf.predict(x_test)

# 评估
print(accuracy_score(y_test, y_pred))

# 查看特征权重
print(wine.feature_names)
print(clf.feature_importances_)

out:

0.9444444444444444
['alcohol', 'malic_acid', 'ash', 'alcalinity_of_ash', 'magnesium', 'total_phenols', 'flavanoids', 'nonflavanoid_phenols', 'proanthocyanins', 'color_intensity', 'hue', 'od280/od315_of_diluted_wines', 'proline']
[0.15919509 0.02198606 0.01433753 0.05345497 0.00382762 0.04298213
 0.14479143 0.00705173 0.0217178  0.20066031 0.10637167 0.10433341
 0.11929024]

四、Adaboost

4.1 简介

Adaboost算法是一种提升方法,将多个弱分类器,组合成强分类器。
AdaBoost,是英文”Adaptive Boosting“(自适应增强)的缩写,由Yoav Freund和Robert Schapire在1995年提出。
它的自适应在于:**前一个弱分类器分错的样本的权值(样本对应的权值)会得到加强,权值更新后的样本再次被用来训练下一个新的弱分类器。**在每轮训练中,用总体(样本总体)训练新的弱分类器,产生新的样本权值、该弱分类器的话语权,一直迭代直到达到预定的错误率或达到指定的最大迭代次数。(在分类不准的情况下再重新划分
总体——样本——个体三者间的关系需要搞清除
总体N。样本:{ni}i从1到M。个体:如n1=(1,2),样本n1中有两个个体。

4.2 算法原理

(1)初始化训练数据(每个样本)的权值分布:如果有N个样本,则每一个训练的样本点最开始时都被赋予相同的权重:1/N。
(2)训练弱分类器。具体训练过程中,如果某个样本已经被准确地分类,那么在构造下一个训练集中,它的权重就被降低;相反,如果某个样本点没有被准确地分类,那么它的权重就得到提高。同时,得到弱分类器对应的话语权。然后,更新权值后的样本集被用于训练下一个分类器,整个训练过程如此迭代地进行下去。
(3)将各个训练得到的弱分类器组合成强分类器。各个弱分类器的训练过程结束后,分类误差率小的弱分类器的话语权较大,其在最终的分类函数中起着较大的决定作用,而分类误差率大的弱分类器的话语权较小,其在最终的分类函数中起着较小的决定作用。换言之,误差率低的弱分类器在最终分类器中占的比例较大,反之较小。

4.3 Adaboost例子

在这里插入图片描述
在这里插入图片描述
解释:sign符号函数,大于0为1小于0为-1。

4.4代码

# adabooost.py
#
import numpy as np
from sklearn import ensemble, neighbors, datasets, preprocessing
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

np.random.RandomState(0)

# 加载数据
wine = datasets.load_wine()

# 划分训练集与测试集
x, y = wine.data, wine.target
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3)

# 数据预处理
scaler = preprocessing.StandardScaler().fit(x_train)
x_train = scaler.transform(x_train)
x_test = scaler.transform(x_test)

# 创建模型
clf = ensemble.AdaBoostClassifier(n_estimators=50)# 提升50次

# 模型拟合
clf.fit(x_train, y_train)

# 预测
y_pred = clf.predict(x_test)

# 评估
print(accuracy_score(y_test, y_pred))
# 0.9444444444444444

五、GBRT回归

5.1 概述

Gradient Tree Boosting 或梯度提升回归树(GBRT)是对于任意的可微损失函数的提升算法的泛化。
GBRT 是一个准确高效的现有程序, 它既能用于分类问题也可以用于回归问题。梯度树提升模型被应用到各种领域,包括网页搜索排名和生态领域。

GBRT 的优点:

  • 对混合型数据的自然处理(异构特征)
  • 强大的预测能力
  • 在输出空间中对异常点的鲁棒性(通过具有鲁棒性的损失函数实现)

Gradient Boost与传统的Boost有着很大的区别,它的每一次计算都是为了减少上一次的残差(residual),而为了减少这些残差,可以在残差减少的梯度(Gradient)方向上建立一个新模型。所以说,在Gradient Boost中,每个新模型的建立是为了使得先前模型残差往梯度方向减少,与传统的Boost算法对正确、错误的样本进行加权有着极大的区别。 **它主要的思想是,每一次建立模型是在之前建立模型损失函数的梯度下降方向。**损失函数(loss function)描述的是模型的不靠谱程度,损失函数越大,则说明模型越容易出错(其实这里有一个方差、偏差均衡的问题,但是这里假设损失函数越大,模型越容易出错)。如果我们的模型能够让损失函数持续的下降,则说明我们的模型在不停的改进,而最好的方式就是让损失函数在其梯度(Gradient)的方向上下降。

5.2 GBRT例子

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.3 代码

import numpy as np
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeRegressor
from sklearn import linear_model
from sklearn import ensemble
# Data set
x = np.array(list(range(1, 11))).reshape(-1, 1)
y = np.array([5.56, 5.70, 5.91, 6.40, 6.80, 7.05, 8.90, 8.70, 9.00, 9.05]).ravel()

# Fit regression model
model1 = ensemble.GradientBoostingRegressor(max_depth=1,n_estimators=20)
model1.fit(x, y)

# Predict
X_test = np.arange(0.0, 10.0, 0.01)[:, np.newaxis]
y_1 = model1.predict(X_test)

# Plot the results
plt.figure()
plt.scatter(x, y, s=20, edgecolor="black", c="darkorange", label="data")
plt.plot(X_test, y_1, color="cornflowerblue", label="max_depth=1", linewidth=2)
plt.xlabel("data")
plt.ylabel("target")
plt.title("Decision Tree Regression")
plt.legend()
plt.show()

在这里插入图片描述

六、Adaboost与GBDT的区别

AdaBoost
(1)提高那些被前一轮弱分类器错误分类样本的权值,而降低那些被正确分类样本的权值。这样一来,那些没有得到正确分类的数据,由于其权值的加大而受到后一轮的弱分类器的更大关注,于是,分类问题就被一系列的弱分类器“分而治之”。

(2)至于第二个问题,即弱分类器的组合,AdaBoost采取加权多数表决的方法。具体地,加大分类误差率小的弱分类器的权值,使其在表决中起较大的作用,减小分类误差率较大的弱分类器的权值,使其在表决中起较小的作用。

GBDT
(1)GBDT和其它Boosting算法一样,通过将表现一般的数个模型(通常是深度固定的决策树)组合在一起来集成一个表现较好的模型。抽象地说,模型的训练过程是对一任意可导目标函数的优化过程。通过反复地选择一个指向负梯度方向的函数,该算法可被看做在函数空间里对目标函数进行优化。因此可以说Gradient Boosting = Gradient Descent + Boosting。
(2)AdaBoost是通过提升错分数据点的权重来定位模型的不足而Gradient Boosting是通过算梯度(gradient)来定位模型的不足。因此相比AdaBoost, Gradient Boosting可以使用更多种类的目标函数,而当目标函数是均方误差时,计算损失函数的负梯度值在当前模型的值即为残差。

七、Xgboost与GBDT的区别

(1) 传统GBDT在优化时只用到一阶导数信息,xgboost则对代价函数进行了二阶泰勒展开,同时用到了一阶和二阶导数。顺便提一下,xgboost工具支持自定义代价函数,只要函数可一阶和二阶求导。例如,xgboost支持线性分类器,这个时候xgboost相当于带L1和L2正则化项的逻辑斯蒂回归(分类问题)或者线性回归(回归问题)

(2) xgboost在代价函数里加入了正则项,用于控制模型的复杂度。正则项里包含了树的叶子节点个数、每个叶子节点上输出的score的L2模的平方和。从Bias-variance tradeoff角度来讲,正则项降低了模型的variance,使学习出来的模型更加简单,防止过拟合,这也是xgboost优于传统GBDT的一个特性。

(3)列抽样(column subsampling)。xgboost借鉴了随机森林的做法,支持列抽样(即每次的输入特征不是全部特征),不仅能降低过拟合,还能减少计算,这也是xgboost异于传统gbdt的一个特性。

(4)并行化处理:在训练之前,预先对每个特征内部进行了排序找出候选切割点,然后保存为block结构,后面的迭代中重复地使用这个结构,大大减小计算量。在进行节点的分裂时,需要计算每个特征的增益,最终选增益最大的那个特征去做分裂,那么各个特征的增益计算就可以开多线程进行,即在不同的特征属性上采用多线程并行方式寻找最佳分割点。

(个人认为后面两个,更改的GBDT也可以做到,相比于GBDT,Xgboost最重要的优点还是用到了二阶泰勒展开信息和加入正则项)
参考:
sklearn实战-----2.随机森林
机器学习实战笔记:AdaBoost

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wa1tzy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值