英语网站建设公司,湛江建设工程造价信息网,建筑模板尺寸规格有几种,肥城网站建设哪家好一、什么是随机森林前面我们已经介绍了决策树的基本原理和使用。但是决策树有一个很大的缺陷#xff1a;因为决策树会非常细致地划分样本#xff0c;如果决策树分得太多细致#xff0c;会导致其在训练集上出现过拟合#xff0c;而如果决策树粗略地划分样本#xff0c;又不…一、什么是随机森林前面我们已经介绍了决策树的基本原理和使用。但是决策树有一个很大的缺陷因为决策树会非常细致地划分样本如果决策树分得太多细致会导致其在训练集上出现过拟合而如果决策树粗略地划分样本又不能很好地拟合样本。为了解决这个两难困境聪明的专家们想出了这样的思路既然我增加单棵树的深度会适得其反那不如我不追求一个树有多高的精确度而是训练多棵这样的树来一块预测一棵树的力量再大也是有限的当他们聚成一个集体它的力量可能是难以想象的也就是我们常说的“三个臭皮匠赛过诸葛亮”。这便是集成学习的思想。这里多提一句正是因为每棵树都能够用比较简单的方法细致地拟合样本我们可以多用几棵树来搭建准确率更高的算法后边要说到的一些工业级的算法比如GBDT、XGBOOST、LGBM都是以决策树为积木搭建出来的。所以在学习这些算法的过程中我们也要把决策树算法看成一块块积木学完了基本的积木算法之后对于现在常用的那几个工业级的算法只需要理清两个问题1这个算法利用了哪个集成学习思想2这个算法具体怎么把这个思想实现出来的。随机森林就是决策树们基于bagging集成学习思想搭建起来的。随机森林的算法实现思路非常简单只需要记住一句口诀抽等量样本选几个特征构建多棵树。下面我们详细解释这个口诀的含义1抽等量样本随机森林训练每棵树之前都会从训练集中随机抽出一部分样本来训练。所以说训练每棵树用到的样本其实都是有差别的这样就保证了不同的树可以重点学习不同的样本。而为了达到抽等量样本的目的抽样方式一般是有放回的抽样也就是说在训练某棵树的时候这一次被抽到的样本会被放回数据集中下一次还可能被抽到因此原训练集中有的样本会多次被抽出用来训练而有的样本可能不会被使用到。但是不用担心有的样本没有用到只要训练的树的棵数足够多大多数训练样本总会被取到的。有极少量的样本成为漏网之鱼也不用担心后边我们会筛选他们出来用来测试模型。2选几个特征在训练某棵树的时候也不是将样本的所有特征都用来训练而是会随机选择一部分特征用来训练。这样做的目的就是让不同的树重点关注不同的特征。在scikit-learn中用“max_features”这个参数来控制训练每棵树选取的样本数。3构建多棵树。通过1、2两个步骤训练多棵树。鲁迅曾经说过世界上本没有森林长得树多了就成了森林。正是一棵棵决策树构成了整个随机森林。具体构建树的数量在scikit-learn中用“n_estimators”这个参数来控制。那最终的预测结果怎么得到呢随机森林是非常民主的算法最终的结果由每棵决策树综合给出如果是分类问题那么对于每个测试集树都会预测出一个类别进行投票最终统计票数多的那个类别为最终类别。看看这算法俨然是一个遵循“少数服从多数”的原则的小型民主社会如果是回归问题那就更简单了各个树得到的结果相加求得一个平均值为最终回归结果。从上边的流程中可以看出随机森林的随机性主要体现在两个方面数据集的随机选取、每棵树所使用特征的随机选取。以上两个随机性使得随机森林中的决策树都能够彼此不同提升系统的多样性从而提升分类性能。二、随机森林的特点以上就是随机森林的构建原理下面我们说说随机森林算法的优缺点1、优点1实现简单泛化能力强可以并行实现因为训练时树与树之间是相互独立的2相比单一决策树能学习到特征之间的相互影响且不容易过拟合3能直接特征很多的高维数据因为在训练过程中依旧会从这些特征中随机选取部分特征用来训练4相比SVM不是很怕特征缺失因为待选特征也是随机选取5训练完成后可以给出特征重要性。当然这个优点主要来源于决策树。因为决策树在训练过程中会计算熵或者是基尼系数越往树的根部特征越重要。2、缺点1在噪声过大的分类和处理回归问题时还是容易过拟合2相比于单一决策树它的随机性让我们难以对模型进行解释。三、随机森林的使用和决策树类似随机森林同样可以分为分类森林RandomForestClassifier 和回归森林RandomForestRegressor在scikit-lean中调用方式和决策树相同。让我们在手写识别数据集上实现一个分类森林。#导入必要的包
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split,GridSearchCV,cross_val_score
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt
import numpy as np#导入数据集
data load_digits()
x data.data
y data.target用随机森林训练并进行交叉验证RF RandomForestClassifier(random_state 66)
score cross_val_score(RF,x,y,cv10).mean()
print(交叉验证得分: %.4f%score)输出交叉验证得分: 0.9278四、随机森林调参一随机森林参数介绍除了和决策树有的参数之外对于随机森林只需要掌握8个新增的参数即可我将这8个参数分成三类1、用于调参的参数max_features最大特征数: 这个参数用来训练每棵树时需要考虑的最大特征个数超过限制个数的特征都会被舍弃默认为auto。可填入的值有int值float特征总数目的百分比“auto”/“sqrt”总特征个数开平方取整,“log2”总特征个数取对数取整。默认值为总特征个数开平方取整。值得一提的是这个参数在决策树中也有但是不重要因为其默认为None即有多少特征用多少特征。为什么要设置这样一个参数呢原因如下考虑到训练模型会产生多棵树如果在训练每棵树的时候都用到所有特征以来导致运算量加大二来每棵树训练出来也可能千篇一律没有太多侧重所以设置这个参数使训练每棵树的时候只随机用到部分特征在减少整体运算的同时还可以让每棵树更注重自己选到的特征。n_estimators随机森林生成树的个数默认为100。2、控制样本抽样参数bootstrap每次构建树是不是采用有放回样本的方式(bootstrap samples)抽取数据集。可选参数True和False默认为True。oob_score是否使用袋外数据来评估模型默认为False。boostrap和 oob_score两个参数一般要配合使用。如果boostrap是False那么每次训练时都用整个数据集训练如果boostrap是True那么就会产生袋外数据。先解释一下袋外数据的概念在一个含有n个样本的原始训练集中我们每次随机取出一个样本并记录并在抽取下一个样本之前将该样本放回原始训练集即下次采样时这个样本依然可能被采集到这样采集n次最终得到一个和原始训练集一样大的子数据集。由于是随机采样这样每次的子数据集和原始数据集都不同用这些子数据集来各自训练一棵树这些树的参数自然也就各不相同了。然而有放回抽样也会有自己的问题。由于是有放回一些样本可能在同一个自助集中出现多次而其他一些却可能被忽略一般来说每一次抽样某个样本被抽到的概率是 1/n 所以不被抽到的概率就是 1-1/n ,所以n个样本都不被抽到的概率就是 用洛必达法则化简可以得到这个概率收敛于(1/e)约等于0.37。因此如果数据量足够大的时候会有约37%的训练数据被浪费掉没有参与建模这些数据被称为袋外数据(out of bag data简写为oob)。为了这些数据不被浪费我们也可以把他们用来作为集成算法的测试集。也就是说在使用随机森林时我们可以不划分测试集和训练集只需要用袋外数据来测试我们的模型即可。当然这需要样本数据n和分类器个数n_estimators都很大如果数据集过少很可能就没有数据掉落在袋外自然也就无法使用oob数据来测试模型了。当bootstrap参数取默认值True时表示抽取数据集时采用这种有放回的随机抽样技术。如果希望用袋外数据来测试则需要在实例化时就将oob_score这个参数调整为True训练完毕之后我们可以用随机森林的另一个重要属性oob_score_来查看我们的在袋外数据上测试的结果代码如下#训练一个模型让oob_scoreTrue
输出0.9393433500278241这个就是没有参与训练的数据集在模型上的测试得分。3、不重要参数max_samples构建每棵树需要抽取的最大样本数据量默认为None即每次抽取样本数量和原数据量相同。n_jobs:设定fit和predict阶段并列执行的CPU核数,如果设置为-1表示并行执行的任务数等于计算机核数。默认为None即采用单核计算。verbose控制构建数过程的冗长度默认为0。一般不需要管这个参数。warm_start当设置为True,重新使用之前的结构去拟合样例并且加入更多的估计器(estimators,在这里就是随机树)到组合器中。默认为 False以上这几个参数只需要简单了解即可大多数参数在使用过称重不用调整只是需要注意一点n_jobs默认为None为了加快速度可以把n_jobs设置为-1。二随机森林调参顺序介绍完了这些参数接下来就要介绍随机森林的调参顺序了随机森林的调参顺序一般遵循先重要后次要、先粗放后精细的原则即先确定需要多少棵树参与建模再对每棵树做细致的调参精益求精。相对于xgboost等算法随机森林的调参还是相对比较简单因为各个参数之间互相影响的程度很小只需要按步骤调整即可。结合我们决策树文章中提到的参数以及今天所讲的两个参数随机森林中主要用来调参的参数有6个n_estimatorscriterionmax_depthmin_samples_splitmin_samples_leafmax_features调参顺序如下1选择criterion参数决策树划分标准和决策树一样这个参数只有两个参数 entropy熵 和 gini基尼系数可选默认为gini这里简单测试一下就好RF RandomForestClassifier(random_state 66)
score cross_val_score(RF,x,y,cv10).mean()
print(基尼系数得分: %.4f%score)
RF RandomForestClassifier(criterion entropy,random_state 66)
score cross_val_score(RF,x,y,cv10).mean()
print(熵得分: %.4f%score)输出基尼系数得分: 0.9278熵得分: 0.9249这里看到依旧是选用gini系数模型效果更好。2探索n_estimators的最佳值。接下来才是进入真正的调参环节。根据上述调参原则我们先看看用几棵树模型的表现最好。一般来说树的棵数越多模型效果表现越好但树的棵数达到一定的数量之后模型精确度不再上升训练这个模型的计算量却逐渐变大。这个时候再加树的数量就没必要了。就好比你饿的时候每吃一个馒头就特别顶饱但是吃到一定数量的馒头之后再吃就要撑着了。只要找到这个临界值这个参数就调好了。为了观察得分随着树增多的变化我们依然绘制决策树调参时的学习曲线。###调n_estimators参数
ScoreAll []
for i in range(10,200,10):DT RandomForestClassifier(n_estimators i,random_state 66) #,criterion entropyscore cross_val_score(DT,data.data,data.target,cv10).mean()ScoreAll.append([i,score])
ScoreAll np.array(ScoreAll)max_score np.where(ScoreAllnp.max(ScoreAll[:,1]))[0][0] ##这句话看似很长的其实就是找出最高得分对应的索引
print(最优参数以及最高得分:,ScoreAll[max_score])
plt.figure(figsize[20,5])
plt.plot(ScoreAll[:,0],ScoreAll[:,1])
plt.show()输出最优参数以及最高得分: [120. 0.95560035]调n_estimators参数根据曲线我们进一步缩小范围搜索100~130之间的得分。这里可以根据经验自己指定###进一步缩小范围调n_estimators参数
ScoreAll []
for i in range(100,130):DT RandomForestClassifier(n_estimators i,random_state 66) #criterion entropy,score cross_val_score(DT,data.data,data.target,cv10).mean()ScoreAll.append([i,score])
ScoreAll np.array(ScoreAll)max_score np.where(ScoreAllnp.max(ScoreAll[:,1]))[0][0] ##这句话看似很长的其实就是找出最高得分对应的索引
print(最优参数以及最高得分:,ScoreAll[max_score])
plt.figure(figsize[20,5])
plt.plot(ScoreAll[:,0],ScoreAll[:,1])
plt.show()输出最优参数以及最高得分: [117. 0.95727946]调n_estimators参数可以看到117为得分最高点我们暂定n_estimators为117接着调下边的参数。3探索max_depth树的最大深度最佳参数###粗调max_depth参数
ScoreAll []
for i in range(10,30,3):DT RandomForestClassifier(n_estimators 117,random_state 66,max_depth i ) #,criterion entropyscore cross_val_score(DT,data.data,data.target,cv10).mean()ScoreAll.append([i,score])
ScoreAll np.array(ScoreAll)max_score np.where(ScoreAllnp.max(ScoreAll[:,1]))[0][0] ##这句话看似很长的其实就是找出最高得分对应的索引
print(最优参数以及最高得分:,ScoreAll[max_score])
plt.figure(figsize[20,5])
plt.plot(ScoreAll[:,0],ScoreAll[:,1])
plt.show()输出最优参数以及最高得分: [16. 0.95727946]max_depth参数转折点在16但是16之后一直没有变化可以说明就算不限制所有树的最大深度也就是16左右因为我们以步长为3搜索的所以还需要进一步搜索一下16附近的值。精细搜索之后发现16这个值就是转折点所以暂定max_depth 16。4探索min_samples_split分割内部节点所需的最小样本数最佳参数min_samples_split最小值就是2我们就从2开始调起。###调min_samples_split参数
ScoreAll []
for i in range(2,10):RF RandomForestClassifier(n_estimators 117,random_state 66,max_depth 16,min_samples_split i ) #,criterion entropyscore cross_val_score(RF,data.data,data.target,cv10).mean()ScoreAll.append([i,score])
ScoreAll np.array(ScoreAll)max_score np.where(ScoreAllnp.max(ScoreAll[:,1]))[0][0] ##这句话看似很长的其实就是找出最高得分对应的索引
print(最优参数以及最高得分:,ScoreAll[max_score])
plt.figure(figsize[20,5])
plt.plot(ScoreAll[:,0],ScoreAll[:,1])
plt.show()输出最优参数以及最高得分: [2. 0.95727946]min_samples_split参数可以看到随着min_samples_split增大模型得分下降说明没有出现过拟合现象min_samples_split暂定2。5探索min_samples_leaf分割内部节点所需的最小样本数最佳参数###调min_samples_leaf参数
ScoreAll []
for i in range(1,15,2):DT RandomForestClassifier(n_estimators 117,random_state 66,max_depth 16,min_samples_leaf i,min_samples_split 2 ) score cross_val_score(DT,data.data,data.target,cv10).mean()ScoreAll.append([i,score])
ScoreAll np.array(ScoreAll)max_score np.where(ScoreAllnp.max(ScoreAll[:,1]))[0][0] ##这句话看似很长的其实就是找出最高得分对应的索引
print(最优参数以及最高得分:,ScoreAll[max_score])
plt.figure(figsize[20,5])
plt.plot(ScoreAll[:,0],ScoreAll[:,1])
plt.show()输出最优参数以及最高得分: [1. 0.95727946]min_samples_leaf参数5对每棵树用到的最大特征数max_features调参:正常来说只要这个值不要设置得太小所有特征都会被整个森林抽取到用来训练 所以相对来说这个值对整个模型的影响不是太大。但这个值越大单棵树需要考虑的特征越多虽然模型的表现可能会更好但是增加这个值会导致算法运行速度变慢所以需要我们考虑去找一个平衡值。#调max_features参数
param_grid {max_features:np.arange(0.1, 1)}rfc RandomForestClassifier(random_state66,n_estimators 117,max_depth 16,min_samples_leaf 1 ,min_samples_split 4 )
GS GridSearchCV(rfc,param_grid,cv10)
GS.fit(data.data,data.target)
print(GS.best_params_)
print(GS.best_score_)输出{max_features: 0.1}0.9560335195530726如果时间充裕接下来也可以将min_samples_leaf和min_samples_split作为网格参数联调一下因为这两个参数会相互影响这里暂时省略这一步。此时我们得到的参数如下参数值n_estimators117max_depth16min_samples_leaf1min_samples_split2max_features0.16在得到的最优参数附近进行小范围网格搜索因为手动调参时这些参数可能会相互影响导致我们得到的参数还不是最优的。所以在最优参数附近进行小范围的网格搜索排出相互影响的因素尤其是在数据集量比较少时小范围搜索一下可能会有意外收获。import time
start time.time()param_grid {n_estimators:np.arange(140, 150),max_depth:np.arange(15, 18),min_samples_leaf:np.arange(1, 8),min_samples_split:np.arange(2, 5),max_features:np.arange(0.1, 1)
}rfc RandomForestClassifier(random_state66)
GS GridSearchCV(rfc,param_grid,cv10)
GS.fit(data.data,data.target)
end time.time()
print(循环运行时间:%.2f秒%(end-start))
print(GS.best_params_)
print(GS.best_score_)输出如下循环运行时间:3052.67秒{max_depth: 16, max_features: 0.1, min_samples_leaf: 1, min_samples_split: 3, n_estimators: 143}0.9599332220367279可以看到精确度又上升了一点此时我们得到的新旧参数对比如下参数旧值新值n_estimators117143max_depth1616min_samples_leaf11min_samples_split23max_features0.10.1对比一下新旧参数可以看到参数变化还是比较大的尤其是树的棵数这个参数。当然这里主要原因是我们用来做示例的这个预置的数据集只有1797条数据导致参数的随机性太大在实际使用中数据集数量都是十万百万级的不会出现我们手动调整的参数和小范围网格搜索参数差别这么大的情况。最后需要说明的一点是随机森林相对于决策树来说运行较慢在调参时可以将参数搜索范围设置得小一些。当然这只是我个人的调参顺序仅用来参考没必要这么固化。实际调参时可以根据实际情况做一些调整。还是那句话正是调参过程充满的各种不确定性才是调参的真正魅力所在。五、本系列相关文章机器学习超详细实践攻略(1)盘点scikit-learn里那些有趣又有用的彩蛋级入门数据集机器学习超详细实践攻略(8)使用scikit-learn构建模型的通用模板【万字长文】机器学习超详细实践攻略(9)决策树算法详解及小白都能看懂的调参指南机器学习超详细实践攻略(21)三板斧干掉样本不均衡问题之1——过欠采样机器学习超详细实践攻略(22)三板斧干掉样本不均衡问题之2——对正负样本设置不同权重机器学习超详细实践攻略(23)三板斧干掉样本不均衡问题之3——通过集成学习方法解决样本不均衡