1.集成算法概述

1.数据上构建多个模型,集成所有模型的建模结果
2.大多数机器学习领域有利用集成学习,现实中集成学习也有很大的作用。如市场营销模拟的建模,统计客户来源、保留和流失,也可用来预测疾病的风险和病患者的易感性
3.各种算法竞赛中,随机森林,梯度提升树(GBDT),Xgboost等集成算法应用很广
4.集成算法会考虑多个评估器的建模结果,汇总之后得到一个综合的结果,以此来获取比单个模型更好的回归或分类表现

通常来说,有三类集成算法:装袋法(Bagging),提升法(Boosting)和stacking

随机森林二元分类 随机森林 二分类_随机森林


装袋法:多个相互独立的评估器,对其预测进行平均或多数表决原则来决定评估的结果。代表模型就是随机森林。

提升法:基评估器是按顺序一一构建的。结合弱评估器对难以评估的样本进行预测构成一个强评估器。代表模型有Adaboost和梯度提升树。

sklearn中的集成算法模块ensemble


类的功能

ensemble.AdaBoostClassifier

AdaBoost分类

ensemble.AdaBoostRegressor

Adaboost回归

ensemble.BaggingClassifier

装袋分类器

ensemble.BaggingRegressor

装袋回归器

ensemble.ExtraTreesClassifier

Extra-trees分类(超树,极端随机树)

ensemble.ExtraTreesRegressor

Extra-trees回归

ensemble.GradientBoostingClassifier

梯度提升分类

ensemble.GradientBoostingRegressor

梯度提升回归

ensemble.IsolationForest

隔离森林

ensemble.RandomForestClassifier

随机森林分类

ensemble.RandomForestRegressor

随机森林回归

ensemble.RandomTreesEmbedding

完全随机树的集成

ensemble.VotingClassifier

用于不合适估算器的软投票/多数规则分类器

2.RandomForestClassifier参数

随机森林二元分类 随机森林 二分类_随机森林二元分类_02

说明:criterion、max_depth、min_samples_leaf、min_samples_split、max_features、min_impuiity_decrease参数和决策树中含义一样。

n_estimators
森林中树木的数量,即基评估器的数量。n_estimators越大,模型的效果往往越好。但任何模型都有决策边界,n_estimators达到一定的程度之后,随机森林的精确性往往开始波动,并且,n_estimators越大,需要的计算量和内存也越大,训练的时间也会越来越长。

random_state
随机森林的本质是装袋集成算法(bagging),是对基评估器的预测结果进行平均或多数表决原则来决定集成评估器的结果。

说明:随机森林中也有random_state,用法和分类树中相似,不过在分类树中,一个random_state只控制生成一棵树,而随机森林中的random_state控制的是生成森林的模式,而非让一个森林中只有一棵树。
rfc = RandomForestClassifier(n_estimators=20,random_state=2)
rfc = rfc.fit(Xtrain, Ytrain)
rfc.estimators_[0].random_state
for i in range(len(rfc.estimators_)):
    print(rfc.estimators_[i].random_state)

随机森林二元分类 随机森林 二分类_sklearn_03


多次运行会得出结果:用袋装法集成时,基分类器应当是相互独立的,是不相同的。即随机森林中生成是一组固定的树,但每棵树依然是不一致的。

bootstrap & oob_score
要让基分类器尽量不同,可以使用不同的训练集来进行训练。袋装法正是通过有放回的随机抽样技术来形成不同的训练数据,bootstrap是用来控制抽样技术的参数。

bootstrap参数默认True,代表采用这种有放回的随机抽样技术

对含有n个样本的原始训练集进行又放回的随机采样,每次采样一个样本,这样采集n次,最终得到和原始训练集一样大的由n个样本组成的自助集。由于是随机采样,每次的自助集和原始数据集不同,和其他的采样集也是不同的。使用互不相同的自助集来训练我们的基分类器,基分类器自然也就各不相同。

随机森林二元分类 随机森林 二分类_随机森林二元分类_04


用袋外数据来测试则oob_score这个参数为True

由于每个参数被抽取到自助集中的概率为:随机森林二元分类 随机森林 二分类_数据_05=随机森林二元分类 随机森林 二分类_sklearn_06=0.632。越37%的样本会被浪费,浪费掉的样本被称为袋外数据(out of bag data,oob)。于是可以在不划分训练集合测试集的情况下利用oob为训练模型,但当n和n_estimators都不够大的时候,可能就没有数据掉落在袋外,自然也就无法使用oob数据来测试模型了。

rfc = RandomForestClassifier(n_estimators=25,oob_score=True)
rfc = rfc.fit(wine.data,wine.target) 
rfc.oob_score_

随机森林二元分类 随机森林 二分类_决策树_07


oob_score_:查看袋外数据上测试的结果

3.随机森林的建立的流程

步骤一:导入数据和库

%matplotlib inline
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_wine
wine = load_wine()
wine.data.shape
wine.target

随机森林二元分类 随机森林 二分类_随机森林_08


步骤二:划分训练集并实例化模型预测

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 = clf.score(Xtest,Ytest)
print("single Tree:{}".format(score_c)
     ,"random Forest:{}".format(score_r))

随机森林二元分类 随机森林 二分类_随机森林_09


步骤三:随机森林和决策树在一次交叉验证中对比

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="Single Tree")
plt.legend()
plt.show()

随机森林二元分类 随机森林 二分类_决策树_10


步骤四:随机森林和决策树在10次交叉验证中的对比

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="RandomForest")
plt.plot(range(1,11),clf_l,label="Single Tree")
plt.legend()
plt.show()

随机森林二元分类 随机森林 二分类_随机森林二元分类_11


步骤五:n_estimators学习曲线

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()

随机森林二元分类 随机森林 二分类_决策树_12

4.其他重要接口和属性

1.随机森林的接口与决策树完全一致,依然有四个常用接口:apply, fit, predict和score。

2.需要注意随机森林的predict_proba接口,该接口返回每个测试样本对应的被分到每一类标签的概率,标签有几个分类就返回几个概率。如果是二分类问题,则predict_proba返回的数值大于0.5的,被分为1,小于0.5的,被分为0。

3.传统的随机森林是利用袋装法中的规则,平均或少数服从多数来决定集成的结果,而sklearn中的随机森林是平均每个样本对应的predict_proba返回的概率,得到一个平均概率,从而决定测试样本的分类

随机森林二元分类 随机森林 二分类_决策树_13

说明:使用Bagging的一个必要条件

基分类器的判断准确率至少要超过随机分类器,即基分类器的判断准确率至少要超过50%。
基分类器的误差率ε和随机森林的误差率之间的图像绘制如下:

import numpy as np
from scipy.special import comb

x = np.linspace(0,1,20)
y = []
for epsilon in np.linspace(0,1,20):
    E = np.array([comb(25,i)*(epsilon**i)*((1-epsilon)**(25-i))
                  for i in range(13,26)]).sum()
    y.append(E)
                  
plt.plot(x,y,"o-",label="when estimators are different")
plt.plot(x,x,"--",color="red",label="if all estimators are same")
plt.xlabel("individual estimator's error")
plt.ylabel("RandomForest's error")
plt.legend()
plt.show()

随机森林二元分类 随机森林 二分类_随机森林_14


可以从图像上看出,当基分类器的误差率小于0.5,即准确率大于0.5时,集成的效果是比基分类器要好的。相反,

当基分类器的误差率大于0.5,袋装的集成算法就失效了。所以在使用随机森林之前,一定要检查,用来组成随机

森林的分类树们是否都有至少50%的预测正确率。

5.随机森林回归API

随机森林二元分类 随机森林 二分类_随机森林_15


参数,属性与接口,全部和随机森林分类器一致。仅有的不同就是回归树与分类树参数Criterion不一致

criterion: 和决策树中的一摸一样

说明:由于随机森林回归不存在一个样本被分到某个类别的概率问题,因此没有predict_proba这个接口
6.随机森林回归填充缺失值实例

使用均值,0,和随机森林回归来填补缺失值,并验证各状况下的拟合状况,找出对使用的数据集来说最佳的缺失值填补方法
步骤一:导入库和数据

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_boston
from sklearn.impute import SimpleImputer
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import cross_val_score

dataset = load_boston()
dataset.data.shape

随机森林二元分类 随机森林 二分类_sklearn_16


步骤二:放入50%的缺失值

#确定缺失数据个数
x_full ,y_full = dataset.data, dataset.target
n_samples = x_full.shape[0]
n_features = x_full.shape[1]
rng = np.random.RandomState(0)
missing_rate = 0.5
n_missing_samples = int(np.floor(n_samples * n_features * missing_rate))
#随机生成行索引和列索引并赋值为nan
missing_features = rng.randint(0,n_features,n_missing_samples)
missing_samples = rng.randint(0,n_samples,n_missing_samples)
x_missing = x_full.copy()
y_missing = y_full.copy()
x_missing[missing_samples,missing_features] = np.nan
#转换成DataFrame,方便后续操作
x_missing = pd.DataFrame(x_missing)

随机森林二元分类 随机森林 二分类_随机森林二元分类_17

7.机器学习中的调参基本思想

范化误差:衡量模型在未知数据上的准确率

当模型在未知数据(测试集或者袋外数据)上表现糟糕时,我们说模型的泛化程度不够,泛化误差大,模型的效果不好。

随机森林二元分类 随机森林 二分类_sklearn_18

图像表明:
模型太复杂,模型就会过拟合,泛化能力就不够,所以泛化误差大。当模型太简单,模型就会欠拟合,拟合能力就不够,所以误差也会大。只有当模型的复杂度刚刚好的才能够达到泛化误差最小的目标。

几条基础结论

  1. 模型太复杂或者太简单,都会让泛化误差高,我们追求的是位于中间的平衡点
  2. 模型太复杂就会过拟合,模型太简单就会欠拟合
  3. 对树模型和树的集成模型来说,树的深度越深,枝叶越多,模型越复杂
  4. 树模型和树的集成模型的目标,都是减少模型复杂度,把模型往图像的左边移动

随机森林中各参数对于范化误差的影响

参数

对模型在未知数据上的评估性能的影响

影响程度

n_estimators

提升至平稳,n_estimators↑,不影响单个模型的复杂度

⭐⭐⭐⭐

max_depth

有增有减,默认最大深度,即最高复杂度,max_depth↓,模型更简单,且向图像的左边移动

⭐⭐⭐

min_samples _leaf

有增有减,默认最小限制1,即最高复杂度,min_samples_leaf↑,模型更简单,且向图像的左边移动

⭐⭐

min_samples _split

有增有减,默认最小限制2,即最高复杂度,min_samples_split↑,模型更简单,且向图像的左边移动

⭐⭐

max_features

有增有减,默认auto,是特征总数的开平方,位于中间复杂度,max_features↓,模型更简单,max_features↑,模型更复杂;max_features是唯一既能让模型更简单,也能让模型更复杂的参数,所以需要考虑我们调参的方向


criterion

有增有减,一般使用gini

看具体情况

偏差和方差

一个集成模型(f)在未知数据集(D)上的泛化误差E(f;D),由方差(var),偏差(bais)和噪声(ε)共同决定

随机森林二元分类 随机森林 二分类_随机森林_19

随机森林二元分类 随机森林 二分类_决策树_20


图像中每个点就是集成算法中的一个基评估器产生的预估值。红色虚线代表预测值的均值,蓝色的线代表数据本来的面貌。

偏差:预测的预测值与真实值的差异,即红点到蓝线的距离。集成算法中,每个基评估其都有自己的偏差,集成评估器的偏差是所有基评估器偏差的均值。模型越精确,偏差越低。

方差:反映模型每一次输出结果与模型预测值的平均水平之间的误差,即红点到红色虚线的距离,衡量模型的稳定性。模型越稳定,方差越低。

偏差/方差关系图

偏差大

偏差小

方差大

模型不适合,换模型

过拟合,模型复杂

方差小

欠拟合,模型简单,稳定但不准确

范化误差小,目标

随机森林二元分类 随机森林 二分类_数据_21


总之:复杂度高,方差高,总泛化误差高;复杂度低,偏差高,总泛化误差高

八、随机森林在乳腺癌数据上的调参

步骤一:导入库和数据

from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

data = load_breast_cancer()
data.data.shape
data.target

随机森林二元分类 随机森林 二分类_随机森林二元分类_22


步骤二:初步建模查看效果

rfc = RandomForestClassifier(n_estimators=100,random_state=90)
score_pre = cross_val_score(rfc,data.data,data.target,cv=10).mean()
score_pre

随机森林二元分类 随机森林 二分类_决策树_23


步骤三:绘制n_estimators增长的学习曲线(首先)

scorel = []
for i in range(0,200,10):
    rfc = RandomForestClassifier(n_estimators=i+1,
                                 n_jobs=-1,
                                 random_state=90)
    score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
    scorel.append(score)
    
print(max(scorel),(scorel.index(max(scorel))*10)+1)
plt.figure(figsize=[20,5])
plt.plot(range(1,201,10),scorel)
plt.show()

随机森林二元分类 随机森林 二分类_随机森林二元分类_24


继续缩小范围找到最佳值:

scorel = []
for i in range(35,45):
    rfc = RandomForestClassifier(n_estimators=i,
                                 n_jobs=-1,
                                 random_state=90)
    score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
    scorel.append(score)
    
print(max(scorel),([*range(35,45)][scorel.index(max(scorel))]))
plt.figure(figsize=[20,5])
plt.plot(range(35,45),scorel)
plt.show()

随机森林二元分类 随机森林 二分类_sklearn_25


步骤四:根据之前讲的调参步骤来调整

max_depth

parm_grid = {'max_depth':np.arange(1,20,1)}
rfc = RandomForestClassifier(n_estimators=39,
                            random_state=90)
GS = GridSearchCV(rfc,parm_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_
GS.best_score_

随机森林二元分类 随机森林 二分类_决策树_26


max_features

parm_grid = {'max_features':np.arange(5,30,1)}
rfc = RandomForestClassifier(n_estimators=39,
                            random_state=90)
GS = GridSearchCV(rfc,parm_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_
GS.best_score_

随机森林二元分类 随机森林 二分类_决策树_27


总之,之后进行的调整如下:

param_grid = {'criterion':['gini', 'entropy']}
param_grid = {'min_samples_split':np.arange(2, 2+20, 1)}
param_grid = {'min_samples_leaf':np.arange(1, 1+10, 1)}
param_grid = {'max_features':np.arange(5,30,1)}
param_grid = {'criterion':['gini', 'entropy']}

它们的模型的准确率都下降了,即整体的泛化误差上升了,这说明模型现在位于图像左边,即泛化误差最低点的左边(偏差为主导的一边)。通常来说,随机森林应该在泛化误差最低点的右边,树模型应该倾向于过拟合,而不是拟合不足。这和数据集本身有关,但也可能是调整的n_estimators对于数据集来说太大,因此将模型拉到泛化误差最低点去了。然而,既然我们追求最低泛化误差,那就保留这个n_estimators,除非有其他的因素,可以帮助我们达到更高的准确率。

最后总结出来模型的最佳参数为:

rfc = RandomForestClassifier(n_estimators=39,random_state=90)
score = cross_val_score(rfc,data.data,data.target,cv=10).mean()