Class2 随机森林

随机森林

  • 概述
  • 随机森林分类
    • 基学习器参数和集成参数
      • 基学习器参数
      • 集成学习参数
    • 重要属性和接口
    • Bonus:Bagging的另一个必要条件
  • 随机森林回归
    • 重要参数,属性与接口
    • 重要属性和接口
  • 采用随机森林进行缺失值填充
    • 概述:为什么可以这样做
    • 代码
  • 机器学习中调参的基本思想
    • 第一步 找目标
      • 泛化误差
    • 在乳腺癌数据上进行调参

概述

随机森林是一种集成学习算法 sklearn中ensemble模块实现集成算法

随机森林是非常具有代表性的Bagging集成算法,它的所有基评估器都是决策树

随机森林分类

class sklearn.ensemble.RandomForestClassifier (n_estimators=10, criterion=’gini’, max_depth=None,
min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=’auto’,
max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, bootstrap=True, oob_score=False,
n_jobs=None, random_state=None, verbose=0, warm_start=False, class_weight=None)

基学习器参数和集成参数

基学习器参数

详见决策树中的参数讲解

criterion max_depth, min_samples_leaf, min_samples_split, max_features, min_impurity_decrease

# 交叉验证验证结果
rfc = RandomForestClassifier(random_state=0,n_estimators=25)
r_cross = cross_val_score(rfc,wine.data,wine.target,cv=10)
print('r_cross',r_cross)

clf = DecisionTreeClassifier(random_state=0)
c_cross = cross_val_score(clf,wine.data,wine.target,cv=10)
print('c_cross',c_cross)

plt.plot(r_cross,label = 'rfc')
plt.plot(c_cross,label = 'clf')
plt.legend()
plt.show()

集成学习参数

n_estimators (基学习器个数)

n_estimators越大,模型的效果往往越好,但是相应的需要的计算量和内存更大,且模型有决策边界

random_state

装袋集成算法是对基评估器的预测结果进行平均或用多数表决原则来决定集成评估器的结果

决策树从最重要的特征中随机选择出一个特征来进行分枝,因此每次生成的决策树都不一样,这个功能由参数random_state控制。

当random_state固定时,随机森林中生成是一组固定的树,但每棵树依然是不一致的,当这种随机性越大的时候,袋装法的效果一般会越来越好。用袋装法集成时,基分类器应当是相互独立的,是不相同的

bootstrap & oob_score

  1. bootstrap:

    1. bootstrap就是用来控制抽样技术的参数(想让基分类器都不一样→通过有放回的随机抽样技术来形成不同的训练数据)
    2. bootstrap参数默认True,代表采用这种有放回的随机抽样技术。通常,这个参数不会被我们设置为False
  2. oob_score(out of bag score)

    1. 在使用随机森林的时候,我们可以不划分测试集和训练集,只需要用袋外的数据来训练样本即可
    2. 只需要在实例化模型的时候将oob_score设置为True,训练完毕后,用oob_score_属性查看即可
    #无需划分训练集和测试集
    rfc = RandomForestClassifier(n_estimators=25,oob_score=True)
    rfc = rfc.fit(wine.data,wine.target)
    #重要属性oob_score_
    rfc.oob_score_
    

重要属性和接口

依然有四个常用接口:apply, fit, predict和score

predict_proba接口

这个接口返回每个测试样本对应的被分到每一类标签的概率

Bonus:Bagging的另一个必要条件

袋装法还有另一个必要条件:基分类器的判断准确率至少要超过随机分类器,即时说,基分类器的判断准确率至少要超过50%

当基分类器的误差率小于0.5,即准确率大于0.5时,集成的效果是比基分类器要好的。相反,当基分类器的误差率大于0.5,袋装的集成算法就失效了,所以在使用随机森林之前,一定要检查,用来组成随机森林的分类树们是否都有至少50%的预测正确率。

随机森林回归

class sklearn.ensemble.RandomForestRegressor (n_estimators=’warn’, criterion=’mse’, max_depth=None,
min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=’auto’,
max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, bootstrap=True, oob_score=False,
n_jobs=None, random_state=None, verbose=0, warm_start=False)

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

重要参数,属性与接口

criterion
回归树衡量分枝质量的指标,支持的标准有三种:
1)输入"mse"使用均方误差mean squared error(MSE),父节点和叶子节点之间的均方误差的差额将被用来作为
特征选择的标准,这种方法通过使用叶子节点的均值来最小化L2损失
2)输入“friedman_mse”使用费尔德曼均方误差,这种指标使用弗里德曼针对潜在分枝中的问题改进后的均方误差
3)输入"mae"使用绝对平均误差MAE(mean absolute error),这种指标使用叶节点的中值来最小化L1损失

重要属性和接口

最重要的属性和接口,都与随机森林的分类器相一致,还是apply, fit, predict和score最为核心

值得一提的是,随机森林回归并没有predict_proba这个接口

from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestRegressor
from sklearn.datasets import load_boston
import sklearn
boston = load_boston()

regressor = RandomForestRegressor(n_estimators=100,random_state=0)
score = cross_val_score(regressor,boston.data,boston.target,cv = 10,scoring='neg_mean_squared_error')
print(score)
# sklearn中模型评估的列表
sorted(sklearn.metrics.SCORERS.keys())

采用随机森林进行缺失值填充

概述:为什么可以这样做

标签和特征是可以相互转换的:

在一个“用地区,环境,附近学校数量”预测“房价”的问题中,我们既可以用“地区”,“环境”,“附近学校数量”的数据来预测“房价”,也可以反过来,用“环境”,“附近学校数量”和“房价”来预测“地区”

具体操作:

对于一个有n个特征的数据来说,其中特征T有缺失值,我们就把特征T当作标签,其他的n-1个特征和原本的标签组成新的特征矩阵

从缺失最少的特征开始补全:

那如果数据中除了特征T之外,其他特征也有缺失值怎么办?

答案是遍历所有的特征,从缺失最少的开始进行填补(因为填补缺失最少的特征所需要的准确信息最少)。

代码

# 导入相关的库文件
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
#总共506*13=6578个数据
X_full, y_full = dataset.data, dataset.target
n_samples = X_full.shape[0]
n_features = X_full.shape[1]
#首先确定我们希望放入的缺失数据的比例,在这里我们假设是50%,那总共就要有3289个数据缺失
rng = np.random.RandomState(0)
missing_rate = 0.5
n_missing_samples = int(np.floor(n_samples * n_features * missing_rate))
#np.floor向下取整,返回.0格式的浮点数
#所有数据要随机遍布在数据集的各行各列当中,而一个缺失的数据会需要一个行索引和一个列索引
#如果能够创造一个数组,包含3289个分布在0~506中间的行索引,和3289个分布在0~13之间的列索引,那我们就可
#以利用索引来为数据中的任意3289个位置赋空值
#然后我们用0,均值和随机森林来填写这些缺失值,然后查看回归的结果如何
missing_features = rng.randint(0,n_features,n_missing_samples)
missing_samples = rng.randint(0,n_samples,n_missing_samples)
#missing_samples = rng.choice(dataset.data.shape[0],n_missing_samples,replace=False)
#我们现在采样了3289个数据,远远超过我们的样本量506,所以我们使用随机抽取的函数randint。但如果我们需要
# 的数据量小于我们的样本量506,那我们可以采用np.random.choice来抽样,choice会随机抽取不重复的随机数,
# 因此可以帮助我们让数据更加分散,确保数据不会集中在一些行中
X_missing = X_full.copy()
y_missing = y_full.copy()
X_missing[missing_samples,missing_features] = np.nan
X_missing = pd.DataFrame(X_missing)
#转换成DataFrame是为了后续方便各种操作,numpy对矩阵的运算速度快到拯救人生,但是在索引等功能上却不如
# pandas来得好用

# 采用0和1填补并查看效果
#使用均值进行填补
from sklearn.impute import SimpleImputer
imp_mean = SimpleImputer(missing_values=np.nan, strategy='mean')
X_missing_mean = imp_mean.fit_transform(X_missing)
#使用0进行填补
imp_0 = SimpleImputer(missing_values=np.nan, strategy="constant",fill_value=0)
X_missing_0 = imp_0.fit_transform(X_missing)
# 使用随机森林填充
X_missing_reg = X_missing.copy()
sortindex = np.argsort(X_missing_reg.isnull().sum(axis=0)).values
for i in sortindex:
    # 构建新特征矩阵和新的标签
    df = X_missing_reg
    fillc = df.iloc[:,i]
    df = pd.concat([df.iloc[:,df.columns!= i],pd.DataFrame(y_full)],axis=1)
    
    simp_metho = SimpleImputer(missing_values  = np.nan,
                        strategy = 'constant',fill_value =0 )
    df_0 =  simp_metho.fit_transform(df)
    
    # 构造训练集和测试集
    Ytrain = fillc[fillc.notnull()]
    Ytest = fillc[fillc.isnull()]
    Xtrain = df_0[Ytrain.index,:]
    Xtest = df_0[Ytest.index,:]
    
    # 使用随机森林进行填补
    rfr= RandomForestRegressor(n_estimators = 100)
    rfr = rfr.fit(Xtrain,Ytrain)
    Ypredict  = rfr.predict(Xtest)
    
    X_missing_reg.loc[X_missing_reg.iloc[:,i].isnull(),i] =  Ypredict
#对所有数据进行建模,取得MSE结果
X = [X_full,X_missing_mean,X_missing_0,X_missing_reg]
mse = []
std = []
for x in X:
    estimator = RandomForestRegressor(random_state=0, n_estimators=100)
    scores = cross_val_score(estimator,x,y_full,scoring='neg_mean_squared_error',
    cv=5).mean()
    mse.append(scores * -1)
# 进行绘制
x_labels = ['Full data',
'Zero Imputation',
'Mean Imputation',
'Regressor Imputation']
colors = ['r', 'g', 'b', 'orange']
plt.figure(figsize=(12, 6))
ax = plt.subplot(111)
for i in np.arange(len(mse)):
    ax.barh(i, mse[i],color=colors[i], alpha=0.6, align='center')
ax.set_title('Imputation Techniques with Boston Data')
ax.set_xlim(left=np.min(mse) * 0.9,
right=np.max(mse) * 1.1)
ax.set_yticks(np.arange(len(mse)))
ax.set_xlabel('MSE')
ax.set_yticklabels(x_labels)
plt.show()

Class2 随机森林_第1张图片

从结果可以看出,使用随机森林来进行缺失值填充,比起其它填充方法,效果很好

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

第一步 找目标

第一步是要找准目标:我们要做什么?‘

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

泛化误差

在机器学习中,我们用来衡量模型在未知数据上的准确率的指标,叫做泛化误差(Genelization error

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

Class2 随机森林_第2张图片

泛化误差与模型复杂度的关系

泛化误差对我们调参的指示:

调参之前,需要首先判断,模型现在处于图像的哪一边

  • 模型太复杂或者太简单,都会让泛化误差高,我们追求的是位于中间的平衡点

  • 模型太复杂就会过拟合,模型太简单就会欠拟合

  • 模型太复杂就会过拟合,模型太简单就会欠拟合,模型太复杂就会过拟合,模型太简单就会欠拟合

    对树模型来说,树越茂盛,深度越深,枝叶越多,模型就越复杂。所以树模型是天生位于图的右上角的模型,随机森林是以树模型为基础,所以随机森林也是天生复杂度高的模型。随机森林的参数,都是向着一个目标去:减少模型的复杂度,把模型往图像的左边移动,防止过拟合。当然了,调参没有绝对,也有天生处于图像左边的随机森林,所以调参之前,我们要先判断,模型现在究竟处于图像的哪一边
    Class2 随机森林_第3张图片

在乳腺癌数据上进行调参

  1. 确定参数对模型的影响程度
  2. 按照影响由大到小依次进行调参(画学习曲线或者进行网格搜索)
  3. 在不确定参数范围的时候,可以先划一个大概的范围(并设置较大的步长),在表现最优的参数值附近缩小步长并再次进行搜索
  4. 最后将参数组合起来进行调参
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()
score_pre
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()
scorel = []
for i in range(65,80):
    rfc = RandomForestClassifier(n_estimators=i,
    n_jobs=-1,
    random_state=90)
    score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
    print(score)
    scorel.append(score)
print(max(scorel),([*range(65,80)][scorel.index(max(scorel))]))
plt.figure(figsize=[20,5])
plt.plot(range(65,80),scorel)
plt.show()
param_grid = {'max_depth':np.arange(1, 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_,GS.best_score_
param_grid = {'max_features':np.arange(5,30,1)}
rfc = RandomForestClassifier(n_estimators=73,max_depth = 8
,random_state=90
)
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_,GS.best_score_
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
                             ,max_depth = 8
                             ,random_state=90
                             ,max_features = 22 
                            )
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_,GS.best_score_
param_grid={'min_samples_split':np.arange(2, 2+20, 1)}
#对于min_samples_split和min_samples_leaf,一般是从他们的最小值开始向上增加10或20
#面对高维度高样本量数据,如果不放心,也可以直接+50,对于大型数据,可能需要200~300的范围
#如果调整的时候发现准确率无论如何都上不来,那可以放心大胆调一个很大的数据,大力限制模型的复杂度
rfc = RandomForestClassifier(n_estimators=73
                             ,max_depth = 8
                             ,random_state=90
                             ,max_features = 22
                             ,min_samples_leaf=1
                            )
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_,GS.best_score_
param_grid={'criterion':['gini', 'entropy']}
#对于min_samples_split和min_samples_leaf,一般是从他们的最小值开始向上增加10或20
#面对高维度高样本量数据,如果不放心,也可以直接+50,对于大型数据,可能需要200~300的范围
#如果调整的时候发现准确率无论如何都上不来,那可以放心大胆调一个很大的数据,大力限制模型的复杂度
rfc = RandomForestClassifier(n_estimators=73
                             ,max_depth = 8
                             ,random_state=90
                             ,max_features = 22
                             ,min_samples_leaf=1
                             ,min_samples_split=2
                            )
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_,GS.best_score_

你可能感兴趣的:(sklearn,python,机器学习)