机器学习——随机森林

随机森林

集成算法概念

集成学习(ensemble learning)是时下非常流行的机器学习算法,它本身不是一个单独的机器学习算法,而是通
过在数据上构建多个模型,集成所有模型的建模结果。

集成算法的目标
集成算法会考虑多个评估器的建模结果,汇总之后得到一个综合的结果,以此来获取比单个模型更好的回归或
分类表现

Python语法
%matplotlib inline
##这一句是IPython的魔法函数,可以在IPython编译器里直接使用,作用是内嵌画图,省略掉plt.show()这一步,直接显示图像。如果不加这一句的话,我们在画图结束之后需要加上plt.show()才可以显示图像。
wine数据集示例
%matplotlib inline
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_wine

wine = load_wine()
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 Forset:{}".format(score_r))

##输出
Single Tree:0.9259259259259259 Random Forset:0.9629629629629629

一个决策树一个随机森林比较他们的得分情况

明显随机森林的分数优于决策树

交叉验证 cross_val_score

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

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

rfc = RandomForestClassifier()
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="DecisionTree")
plt.legend()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TcEkaQbh-1678254439867)(D:\Typroa\photo\image-20230118200559230.png)]

##另外一种,10组交叉验证100次交叉验证求均值,更稳定可靠
rfc_l=[]
clf_l=[]
for i in range(10):
    rfc1 = RandomForestClassifier()
    rfc_s1 = cross_val_score(rfc1,wine.data,wine.target,cv=10).mean()
    rfc_l.append(rfc_s1)
    clf1 = DecisionTreeClassifier()
    clf_s1 = cross_val_score(clf,wine.data,wine.target,cv=10).mean()
    clf_l.append(clf_s1)
plt.plot(range(1,11),rfc_l,label="RandomForest1")
plt.plot(range(1,11),clf_l,label="DecisionTree1")
plt.legend()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-82nvOAOs-1678254439868)(D:\Typroa\photo\randomTree.png)]

可以发现下面的曲线比上面的曲线更加平稳,因为上面的只是做了一组交叉验证,会有比较大的误差波动,而下面的是做了十组较稳定

n_estimators的学习曲线

这是森林中树木的数量,即基基评估器的数量。这个参数对随机森林模型的精确性影响是单调的,n_estimators
越大,模型的效果往往越好。但是相应的,任何模型都有决策边界,n_estimators达到一定的程度之后,随机森林
的精确性往往不在上升或开始波动,并且,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()

##输出
0.9888888888888889 9
最大分数是0.9888888888888889
在n_estimators为9的时候取到

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vxyn9Joy-1678254439868)(D:\Typroa\photo\n_estimators.png)]

随机森林本质思考
import numpy as np
from scipy.special import comb
np.array([comb(25,i)*(0.2**i)*((1-0.2)**(25-i)) for i in range(13,26)]).sum()
##输出
0.00036904803455582827
rfc=RandomForestClassifier(n_estimators=25,random_state=2)
rfc=rfc.fit(Xtrain,Ytrain)
## estimators_s是查看树的属性
for i in range(len(rfc.estimators_)):
    print(rfc.estimators_[i].random_state)
##输出
1872583848
794921487
111352301
1853453896
213298710
1922988331
1869695442
2081981515
1805465960
1376693511
1418777250
663257521
878959199
854108747
512264917
515183663
1287007039
2083814687
1146014426
570104212
520265852
1366773364
125164325
786090663
578016451

可以发现每棵树是不一样的

##无需划分训练集和测试集
rfc = RandomForestClassifier(n_estimators=25,oob_score=True)
rfc = rfc.fit(wine.data,wine.target)
##袋外数据的得分
rfc.oob_score_
##输出
0.9719101123595506
Bagging的一个必要条件
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()

调参

模型调参,第一步是要找准目标:我们要做什么?一般来说,这个目标是提升某个模型评估指标,比如对于随机森林来说,我们想要提升的是模型在未知数据上的准确率(由score或oob_score_来衡量)。找准了这个目标,我们就需要思考:模型在未知数据上的准确率受什么因素影响?在机器学习中,我们用来衡量模型在未知数据上的准确率的指标,叫做泛化误差

  • 泛化误差

当模型在未知数据(测试集或者袋外数据)上表现糟糕时,我们说模型的泛化程度不够,泛化误差大,模型的效果不好。泛化误差受到模型的结构(复杂度)影响。看下面这张图,它准确地描绘了泛化误差与模型复杂度的关系,当模型太复杂,模型就会过拟合,泛化能力就不够,所以泛化误差大。当模型太简单,模型就会欠拟合,拟合能力就不够,所以误差也会大

随机森林在乳腺癌数据上的调参
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()
rfc = RandomForestClassifier(n_estimators=100,random_state=90)
score_pre = cross_val_score(rfc,data.data,data.target,cv=10).mean() ##交叉验证输出 0.9648809523809524

第一次的学习曲线,可以先用来帮助我们划定范围,我们取每十个数作为一个阶段,来观察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()

##输出 0.9631265664160402 71

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qMW9RvXv-1678254439870)(D:\Typroa\photo\es1.png)]

然后缩小范围在65-75这个区间

scorel = []
for i in range(65,75):
    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(65,75)][scorel.index(max(scorel))]))
plt.figure(figsize=[20,5])
plt.plot(range(65,75),scorel)
plt.show()

##输出0.9666353383458647 73

调整max_depth

param_grid = {'max_depth':np.arange(1, 20, 1)}
# 一般根据数据的大小来进行一个试探,乳腺癌数据很小,所以可以采用1~10,或者1~20这样的试探
# 但对于像digit recognition那样的大型数据来说,我们应该尝试30~50层深度(或许还不足够
rfc = RandomForestClassifier(n_estimators=73
                            ,random_state=90
                            )
GS = GridSearchCV(rfc,param_grid,cv=10) ##网格搜索
GS.fit(data.data,data.target)
GS.best_params_  ##输出{'max_depth': 8}
GS.best_score_   ##输出 0.9666353383458647

调整min_samples_leaf

param_grid={'min_samples_leaf':np.arange(1, 1+10, 1)}
#对于min_samples_split和min_samples_leaf,一般是从他们的最小值开始向上增加10或20
#面对高维度高样本量数据,如果不放心,也可以直接+50,对于大型数据,可能需要200~300的范围
#如果调整的时候发现准确率无论如何都上不来,那可以放心大胆调一个很大的数据,大力限制模型的复杂度
rfc = RandomForestClassifier(n_estimators=73
                            ,random_state=90
                            )
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_  ##输出{'min_samples_leaf': 1}
GS.best_score_   ##输出0.9666353383458647

调整min_samples_split

param_grid={'min_samples_split':np.arange(2, 2+20, 1)}
rfc = RandomForestClassifier(n_estimators=73
                            ,random_state=90
                            )
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_  ##输出{'min_samples_split': 2}
GS.best_score_   ##输出0.9666353383458647

我们发现调整这三个参数模型的准确率都是不变的

#调整max_features
param_grid = {'max_features':np.arange(5,30,1)}
"""
max_features是唯一一个即能够将模型往左(低方差高偏差)推,也能够将模型往右(高方差低偏差)推的参数。我们需要根据调参前,模型所在的位置(在泛化误差最低点的左边还是右边)来决定我们要将max_features往哪边调。
现在模型位于图像左侧,我们需要的是更高的复杂度,因此我们应该把max_features往更大的方向调整,可用的特征越多,模型才会越复杂。max_features的默认最小值是sqrt(n_features),因此我们使用这个值作为调参范围的最小值。
"""
rfc = RandomForestClassifier(n_estimators=73
                            ,random_state=90
                            )
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_  #输出 {'max_features': 24}
GS.best_score_	 #输出 0.9666666666666668

发现准确率是有提升的,所以最后的参数是

rfc = RandomForestClassifier(n_estimators=73
                            ,random_state=90
                            ,max_features=24
                            )
score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
score - score_pre  ##输出0.0017857142857143904  即调参后增加的准确率
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值