【2 - 随机森林 - 原理部分】菜菜sklearn机器学习

课程地址:《菜菜的机器学习sklearn课堂》_哔哩哔哩_bilibili

  • 第一期:sklearn入门 & 决策树在sklearn中的实现
  • 第二期:随机森林在sklearn中的实现
  • 第三期:sklearn中的数据预处理和特征工程
  • 第四期:sklearn中的降维算法PCA和SVD
  • 第五期:sklearn中的逻辑回归
  • 第六期:sklearn中的聚类算法K-Means
  • 第七期:sklearn中的支持向量机SVM(上)
  • 第八期:sklearn中的支持向量机SVM(下)
  • 第九期:sklearn中的线性回归大家族
  • 第十期:sklearn中的朴素贝叶斯
  • 第十一期:sklearn与XGBoost
  • 第十二期:sklearn中的神经网络

目录

概述

(一)集成算法概述

(二)sklearn中的集成算法 

随机森林分类器RandomForestClassifier

重要参数

(一)控制基评估器的参数

(二)n_estimators(森林中树木的数量/基评估器的数量)

(三)random_state(生成一个固定的森林的模式,控制随机性的参数)

(四)bootstrap(控制抽样技术) & oob_score(使用oob数据来测试)

重要属性和接口

(一)属性

(二)接口

随机森林回归 RandomForestRegressor

重要参数、属性与接口

(一)criterion(回归树衡量分枝质量的指标) 

(二)重要属性和接口

实例:用随机森林回归填补缺失值

(一)导入需要的库

(二)导入完整的数据集并探索

(三)为完整数据集放入缺失值

(四)使用0和均值填补缺失值 

(五)使用随机森林回归填补缺失值

(六)对填补好的数据进行建模

(七)用所得结果画出条形图


概述

(一)集成算法概述

集成学习(ensemble learning)本身不是一个单独的机器学习算法,而是通过在数据上构建多个模型,集成所有模型的建模结果。如随机森林、梯度提升树(GBDT)、XGBoost等

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

  • 多个模型集成的模型 —— 集成评估器(ensemble estimator)
  • 组成集成评估器的每个模型 —— 基评估器(base estimator)

有三类集成算法:

  • Bagging(装袋法):构建多个相互独立的评估器,对其预测进行平均多数表决原则来决定集成评估器的结果。代表模型:随机森林
  • Boosting(提升法):基评估器是相关的,按顺序一一构建,核心思想是结合弱评估器的力量一次次对难以评估的样本进行预测,从而构成一个强评估器(对判断错误的样本在下一次采样的时候会增加权重)。代表模型:Adaboost、梯度提升树
  • Stacking(堆叠法)

 【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第1张图片 

Bagging的另一个必要条件


在使用袋装法时要求基评估器要尽量独立

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


基于随机森林的准确率公式:
【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第2张图片

画出基分类器的误差率 epsilon 和随机森林的误差率之间的图像: 

import numpy as np
from scipy.special import comb  # 求组合
import matplotlib.pyplot as plt
 
x = np.linspace(0,1,20)   # 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()

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第3张图片


从图像上可以看出,当基分类器的误差率小于0.5,即准确率大于0.5时,集成的效果是比基分类器好的;相反,当基分类器的误差率大于0.5,袋装的集成算法就失效了

所以,在使用随机森林之前,一定要检查,用来组成随机森林的分类树们是否都有至少50%的预测正确率

(二)sklearn中的集成算法 

sklearn中的集成算法模块ensemble

  • 类ensemble.RandomForestClassifier:随机森林分类
  • 类ensemble.RandomForestRegressor:随机森林回归

集成算法中,有一半以上都是树的集成模型,可以想见决策树在集成中必然有很好的效果

决策树:可以同时被用于分类回归问题。决策树的主要功能是从一张有特征标签的表格中,通过对特定特征进行提问,总结出一系列决策规则,并用树状图来呈现这些决策规则

  • 决策树非常容易过拟合(很容易在训练集上表现优秀,却在测试集上表现糟糕)
  • 为了防止决策树的过拟合,要对决策树进行剪枝(sklearn提供了大量的剪枝参数)

随机森林是Bagging集成算法,它所有的基评估器都是决策树,分类树组成的森林就叫做随机森林分类器,回归树组成的森林就叫做随机森林回归器。但随机森林是无法被可视化的 


随机森林分类器 RandomForestClassifier

sklearn.ensemble.RandomForestClassifier — scikit-learn 1.2.0 documentation

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第4张图片 

重要参数

(一)控制基评估器的参数

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第5张图片

单个决策树的准确率越高,随机森林的准确率也会越高,因为袋装法是依赖于平均值或少数服从多数原则来决定集成结果的

 

(二)n_estimators(森林中树木的数量/基评估器的数量)

n_estimators越大,模型的效果往往越好(但要在训练难度和模型效果之间取得平衡)

默认值为100(1~200之间比较合适)

  • 任何模型都有决策边界,n_estimators达到一定程度后,随机森林的精确性往往不再上升或开始波动
  • n_estimators越大,需要的计算量和内存也越大,训练的时间也会越来越长

例:随机森林和单个决策树效益的对比(红酒数据集)

# 画图时需要该环境,把页面导入该环境,有助于画图
%matplotlib inline   

from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_wine   # datasets模块导入数据的固有格式是字典

wine = load_wine()

'''
sklearn建模的基本流程:
(1)实例化,即在类里填上参数
(2)把训练集代入实例化后的模型去进行训练,使用的接口是fit
(3)使用其他接口将测试集导入我们训练好的模型,去获取我们希望获取的结果(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)    # random_state控制树的生成模式。决策树自带随机性,输入random_state后只能生成一棵树
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)
     )

  

 

画出随机森林和决策树在一组交叉验证(10折即10次)下的效果对比:

#目的是带大家复习一下交叉验证 cross_val_score
#交叉验证:是数据集划分为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")    # range(1,11)为x轴的取值
plt.plot(range(1,11),clf_s,label = "Decision Tree")
plt.legend()
plt.show()

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第6张图片

#====================一种更加有趣也更简单的写法===================#
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"

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第7张图片 

可以看出RandomForest曲线一直都在DecisionTree曲线上,但差距没有那么大。我们加大训练次数来看看:

# 画出随机森林和决策树在十组交叉验证(10折,100次)下的效果对比
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()
 
#是否有注意到,单个决策树的波动轨迹和随机森林一致?
#再次验证了我们之前提到的,单个决策树的准确率越高,随机森林的准确率也会越高
#随着训练次数上升,随机森林的效果会比决策树好很多

 【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第8张图片 

 

# 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)
    
# list.index(object)返回对象object在列表list当中的索引,返回的是i
print(max(superpa),superpa.index(max(superpa))+1)  # 打印出:最高精确度取值,superpa.index(max(superpa))+1指的是森林中树的数量,即n_estimators
plt.figure(figsize=[20,5])
plt.plot(range(1,201),superpa)
plt.show()

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第9张图片 

(三)random_state(生成一个固定的森林的模式,控制随机性的参数)

Q:随机森林用了什么方法来保证集成的效果一定好于单个分类器?

在刚才的红酒例子中,建立了25棵树。对任何一个样本而言,平均或多数表决原则下,当且仅当有13棵以上的树判断错误的时候,随机森林才会判断错误

单独一棵决策树对红酒数据集的分类准确率在0.85上下浮动。假设一棵树判断错误的可能性为0.2,那13棵树以上都判断错误的可能性是: 

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

  

可见判断错误的几率非常小,这让随机森林在红酒数据集上的表现远远好于单棵决策树

Q:袋装法服从多数表决原则或对基分类器结果求平均,这意味着,默认森林中的每棵树应该是不同的,并且会返回不同的结果(若随机森林里所有的树的判断结果都一致:全判断对或全判断错,那随机森林无论应用何种集成原则来求结果,都应该无法比单棵决策树取得更好的效果)。但我们使用了一样的类DecisionTreeClassifier、一样的参数、一样的训练集和测试集,为什么随机森林里的众多树会有不同的判断结果?

A:sklearn中的分类树DecisionTreeClassifier自带随机性,所以随机森林中的树天生就都是不一样的(决策树从最重要的特征中随机选择出一个特征来进行分枝,因此每次生成的决策树都不一样,这个功能由参数random_state控制) 

  • 在分类树中,一个random_state只控制生成一棵树
  • 随机森林中的random_state控制的是生成森林的模式(生成一片固定的森林,但森林里的每一棵树是不同的),而非让一个森林中只有一棵树
rfc = RandomForestClassifier(n_estimators=20,random_state=2)
rfc = rfc.fit(Xtrain, Ytrain)

#随机森林的重要属性之一:estimators_,查看森林中树的状况(只有random_state不一样)
for i in range(len(rfc.estimators_)):   # len(rfc.estimators_)为20
    print(rfc.estimators_[i].random_state)

 【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第10张图片 

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第11张图片

当random_state固定时,随机森林中生成是一组固定的树,但每棵树依然是不一致的,这是用“随机挑选特征进行分枝”的方法得到的随机性。当这种随机性越大,袋装法的效果一般会越好。用袋装法集成时,基分类器应当是相互独立、不相同的

但这种做法的局限性是很强的,当需要成千上万棵树时,数据不一定能提供成千上万的特征来让我们构建尽量多且不同的树。因此除了random_state,还需要其他随机性

(四)bootstrap(控制抽样技术) & oob_score(使用oob数据来测试)

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

在一个含有n个样本的原始训练集中,进行有放回的随机抽样,采集n次,最终得到一个和原始训练集一样大的、n个样本组成的自助集。每次的自助集和原始数据集以及其他采样集都不同,用这些自助集来训练基分类器,自然基分类器也就不同了

  • 采m个自助集(m即随机森林中树的个数)
  • 每个自助集中都采集n个样本

bootstrap参数默认True,代表采用这种有放回的随机抽样技术(通常不会被设置为False)

由于是有放回,一些样本可能在同一自助集中出现多次,而其他一些却可能被忽略。一般来说,自助集大约平均会包含63%的原始数据,因此会有约37%的训练数据被浪费掉,没有参与建模,这些数据被称为袋外数据(out of bag data,缩写为oob)

除了最开始就划分好的测试集外,oob也可以被用来作为集成算法的测试集。即:在使用随机森林时,可以不划分测试集和训练集,只需要用袋外数据来测试模型即可(但当训练集样本数n 和 基评估器数n_estimators 都不够大的时候,很可能就没有数据掉落在袋外,自然也就无法使用 oob数据来测试模型了)

  • 一个自助集里(n个样本),n次抽样都抽到这个样本的概率为:(1/n)^n

一个自助集里,只要n次中有一次抽到这个样本,这个样本就算是被抽到

  • 一个自助集里,这个样本永远不会被抽到的概率是:(1-1/n)^n
  • 每一个样本被抽到某个自助集中的概率为:1 - (1-1/n)^n 。 当n足够大时,这个概率收敛于 1-1/e ≈ 0.632
  • 如果希望用 oob数据 来测试,则需要在实例化时将 oob_score 这个参数调整为True(默认为False)
  • 训练完毕之后,可以用随机森林的另一个重要属性 oob_score_ 来查看在袋外数据上测试的结果
  • 可以用袋外数据测试,也可以划分训练集和测试集再交叉验证
#无需划分训练集和测试集
rfc = RandomForestClassifier(n_estimators=25,oob_score=True)#默认为False
rfc = rfc.fit(wine.data,wine.target)
 
#重要属性oob_score_
rfc.oob_score_

  

总结:四个参数n_estimators、random_state、boostrap、oob_score(装袋法)

重要属性和接口

(一)属性

  • .estimators_:查看森林中每棵树的情况(主要是看random_state)
  • .oob_score_:查看用袋外数据测试模型的结果
  • .feature_importances_:查看每个特征的重要性得分

(二)接口

  • apply:输入测试集,返回测试集中每一个样本在每一棵树中的叶子节点的索引
  • fit
  • predict
  • score
  • predict_proba:返回每个测试样本对应的被分到每一类标签的概率,标签有几个分类就返回几个概率。如果是二分类问题,则返回的数值大于0.5的被分为1,小于0.5的被分为0
  1. 传统的随机森林是利用装袋法中的规则,平均或少数服从多数来决定集成的结果
  2. sklearn中的随机森林是平均每个样本对应的predict_proba返回的概率,得到一个平均概率,从而决定测试样本的分类
rfc = RandomForestClassifier(n_estimators=25)
rfc = rfc.fit(Xtrain, Ytrain)
rfc.score(Xtest,Ytest)
 
rfc.feature_importances_#结合zip可以对照特征名字查看特征重要性,参见上节决策树

[*zip(wine.feature_names,rfc.feature_importances_)]

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第12张图片

rfc.apply(Xtest)#apply返回每个测试样本所在的叶子节点的索引

 【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第13张图片 

rfc.predict(Xtest)#predict返回每个测试样本的分类/回归结果

rfc.predict_proba(Xtest)

 【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第14张图片 


随机森林回归 RandomForestRegressor

sklearn.ensemble.RandomForestRegressor — scikit-learn 1.2.0 documentation

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第15张图片

与 RandomForestClassifier 的不同:

  1. 不纯度指标criterion:分类树是gini系数或信息熵,回归树是均方误差MSE
  2. 衡量指标:分类树是准确率accuracy,回归树是R²或MSE 

重要参数、属性与接口

(一)criterion(回归树衡量分枝质量的指标) 

三种:

  1. mse(默认):均方误差MSE
  2. friedman_mse:费尔德曼均方误差
  3. mae:绝对平均误差MAE

(二)重要属性和接口

回归树的接口score返回的是R²(可正可负),不是MSE(永远为正,但sklearn中使用的是负均方误差 neg_mean_squared_error)

from sklearn.datasets import load_boston    #一个标签是连续型变量的数据集
from sklearn.model_selection import cross_val_score   #导入交叉验证模块
from sklearn.ensemble import RandomForestRegressor  #导入随机森林回归
 
boston = load_boston()
regressor = RandomForestRegressor(n_estimators=100,random_state=0)#实例化
cross_val_score(regressor, boston.data, boston.target, cv=10
               ,scoring = "neg_mean_squared_error"    #如果不写scoring,回归评估默认是R平方
               )

返回十次交叉验证的结果。如果不填写 scoring="neg_mean_squared_error",交叉验证默认的模型衡量指标是R²(可正可负);而如果写上 scoring,则衡量标准是负MSE(只能为负) 

#sklearn当中的模型评估指标(打分性质)列表
import sklearn
sorted(sklearn.metrics.SCORERS.keys())  #这些指标是scoring可选择的参数

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第16张图片

实例:用随机森林回归填补缺失值

使用 sklearn.impute.SimpleImputer 将均值、中值、或者其他最常用的数值填补到数据中

本案例以波士顿数据集为例,使用均值、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  #数据的特征矩阵
dataset.target  #查看数据标签
dataset.data.shape  #数据的结构
#总共506*13=6578个数据

X_full, y_full = dataset.data, dataset.target
n_samples = X_full.shape[0]  #506
n_features = X_full.shape[1]  #13

(三)为完整数据集放入缺失值

  • 首先确定我们希望放入的缺失数据的比例,在这里我们假设是50%,那总共就要有3289个数据缺失
  • 所有数据要随机遍布在数据集的各行各列当中,而一个缺失的数据会需要一个行索引和一个列索引(一共有506行 13列)
  • 如果能够创造一个数组,包含3289个分布在0~506中间的行索引,和3289个分布在0~13之间的列索引,那我们就可以利用索引来为数据中的任意3289个位置赋空值
  • 然后我们用0,均值和随机森林回归来填写这些缺失值,查看回归的结果如何
rng = np.random.RandomState(0)  #设置一个随机种子,方便观察
missing_rate = 0.5
n_missing_samples = int(np.floor(n_samples * n_features * missing_rate))  #3289
#np.floor向下取整,返回.0格式的浮点数

missing_features = rng.randint(0,n_features,n_missing_samples)  #randint(下限,上限,n)指在下限和上限之间取出n个整数
len(missing_features) #3289

missing_samples = rng.randint(0,n_samples,n_missing_samples)
len(missing_samples) #3289

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第17张图片

对比 np.random.RandomState(0).randint() 和 np.random.RandomState(0).choice()

  • .randint(下限,上限,n):在下限和上限之间取出n个整数

我们现在采样了3289个数据,远远超过我们的样本量506,所以我们使用随机抽取的函数randint

但如果我们需要的数据量小于我们的样本量506,那我们可以采用np.random.choice来抽样

  • choice会随机抽取不重复的随机数,因此可以帮助我们让数据更加分散,确保数据不会集中在一些行中

这里我们不采用np.random.choice,因为我们现在采样了3289个(n_missing_samples)数据,远远超过我们的样本量506(n_samples),使用np.random.choice会报错
 

missing_samples = rng.choice(n_samples,n_missing_samples,replace=False)  # replace=False意味着不重复
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来得好用
X_missing.head()

#并没有对y_missing进行缺失值填补,原因是有监督学习,不能缺标签啊

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第18张图片

(四)使用0和均值填补缺失值 

#使用0进行填补
imp_0 = SimpleImputer(missing_values=np.nan, strategy="constant",fill_value=0)
# strategy有mean均值/median中位数/most_frequent众数/constant常数等
X_missing_0 = imp_0.fit_transform(X_missing)

#使用均值进行填补
imp_mean = SimpleImputer(missing_values=np.nan, strategy='mean')  #实例化
X_missing_mean = imp_mean.fit_transform(X_missing)  #特殊的接口fit_transform = 训练fit + 导出predict

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第19张图片

# 检查是否还有缺失值
pd.DataFrame(X_missing_mean).isnull()  # isnull()是对DataFrame类型,而输出的X_missing_mean是ndarray类型

# 上述方法在数据量大的时候还是看不全
pd.DataFrame(X_missing_mean).isnull().sum()  # 布尔值False为0,True为1. 如果求和为0可以彻底确认没有NaN

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第20张图片

(五)使用随机森林回归填补缺失值

回归填补缺失值的基本思想:任何回归都是从特征矩阵中学习,然后求解连续型标签y的过程。实际上,特征和标签是可以相互转换的

对于一个有n个特征的数据来说,其中特征T有缺失值,就把特征T当做标签,其他的n-1个特征和原本的标签组成新的特征矩阵。对于T来说,它没有缺失的部分就是Y_test,这部分数据既有标签也有特征,而它缺失的部分,只有特征没有标签,就是我们需要预测的部分

  • 特征T不缺失的值对应的其他n-1个特征 + 本来的标签:X_train
  • 特征T不缺失的值:Y_train
  • 特征T缺失的值对应的其他n-1个特征 + 本来的标签:X_test
  • 特征T缺失的值:未知,我们需要预测的Y_test

这种做法对于某一个特征大量缺失,其他特征却很完整的情况,非常适用。但是如果数据中除了特征T之外,其他特征也有缺失值怎么办?

  • 遍历所有特征,从缺失最少的开始填补(因为填补缺失最少的特征所需要的准确信息最少)
  • 填补一个特征时,先将其他特征的缺失值用0代替,每完成一次回归预测,就将预测值放到原本的特征矩阵中,再继续填补下一个特征。每一次填补完毕,有缺失值的特征会减少一个,所以每次循环后,需要用0来填补的特征就越来越少
  • 当进行到最后一个特征时(这个特征应该是所有特征中缺失值最多的),已经没有任何的其他特征需要用0来进行填补了,而我们已经使用回归为其他特征填补了大量有效信息,可以用来填补缺失最多的特征
  • 遍历所有的特征后,数据就完整,不再有缺失值了
X_missing_reg = X_missing.copy()

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第21张图片

# 值越大,表明该列NaN越多
X_missing_reg.isnull().sum(axis=0)   # axis=0表示按列

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第22张图片

# 返回缺失值数量从小到大的特征列的索引
np.argsort(X_missing_reg.isnull().sum(axis=0))

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第23张图片

# 转化成ndarray格式
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)#新特征矩阵
    
    #在新特征矩阵中,对含有缺失值的列,进行0的填补
    df_0 =SimpleImputer(missing_values=np.nan,strategy='constant',fill_value=0).fit_transform(df)
                        
    #找出我们的训练集和测试集
    Ytrain = fillc[fillc.notnull()]# Ytrain是被选中要填充的特征中(现在是我们的标签),存在的那些值:非空值
    Ytest = fillc[fillc.isnull()]#Ytest 是被选中要填充的特征中(现在是我们的标签),不存在的那些值:空值。注意我们需要的不是Ytest的值,需要的是Ytest所带的索引
    Xtrain = df_0[Ytrain.index,:]#在新特征矩阵上,被选出来的要填充的特征的非空值所对应的记录
    Xtest = df_0[Ytest.index,:]#在新特征矩阵上,被选出来的要填充的特征的空值所对应的记录
    
    #用随机森林回归来填补缺失值
    rfc = RandomForestRegressor(n_estimators=100)#实例化
    rfc = rfc.fit(Xtrain, Ytrain)#导入训练集进行训练
    Ypredict = rfc.predict(Xtest)#用predict接口将Xtest导入,得到我们的预测结果(回归结果),就是我们要用来填补空值的这些值
    
    #将填补好的特征返回到我们的原始的特征矩阵中
    X_missing_reg.loc[X_missing_reg.iloc[:,i].isnull(),i] = Ypredict

#检验是否有空值
X_missing_reg.isnull().sum()  # 全部为0则没有空值

以索引为6的特征列(sortindex的第一个)为例,看一下随机森林回归的填充过程:

df = X_missing_reg

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第24张图片

fillc = df.iloc[:,6]
fillc  # 新标签(被选中去填充的特征)

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第25张图片

df = pd.concat([df.iloc[:,df.columns != 6],pd.DataFrame(y_full)],axis=1)  # pd.concat()第一个参数是列表
df  # 新特征矩阵(没有被选中去填充的特征+原始的标签)

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第26张图片

#在新特征矩阵中,对含有缺失值的列,进行0的填补
df_0 = SimpleImputer(missing_values=np.nan,strategy='constant',fill_value=0).fit_transform(df)
df_0

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第27张图片

#找出训练集和测试集
Ytrain = fillc[fillc.notnull()]  # Ytrain是被选中要填充的特征中(现在是我们的标签),存在的那些值:非空值
Ytest = fillc[fillc.isnull()]  # Ytest是被选中要填充的特征中(现在是我们的标签),不存在的那些值:空值。注意我们需要的不是Ytest的值,需要的是Ytest所带的索引
Xtrain = df_0[Ytrain.index,:]  # 在新特征矩阵上,被选出来的要填充的特征的非空值所对应的记录
Xtest = df_0[Ytest.index,:]  # 在新特征矩阵上,被选出来的要填充的特征的空值所对应的记录

#用随机森林回归来填补缺失值
rfc = RandomForestRegressor(n_estimators=100)  #实例化
rfc = rfc.fit(Xtrain, Ytrain)  #导入训练集进行训练
Ypredict = rfc.predict(Xtest)  #用predict接口将Xtest导入,得到我们的预测结果(回归结果),就是我们要用来填补空值的这些值

#将填补好的特征返回到原始的特征矩阵中(用Ypredict去覆盖Ytest里的空值)
#取出X_missing_reg.iloc[:,6].isnull()为True的行
X_missing_reg.loc[X_missing_reg.iloc[:,6].isnull(),6] = Ypredict

(六)对填补好的数据进行建模

#对所有数据进行建模,取得MSE结果
 
X = [X_full,X_missing_mean,X_missing_0,X_missing_reg]   # X_full = dataset.data
 
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()  # y_full是标签
    mse.append(scores * -1)

[*zip(['Full data','Mean Imputation','Zero Imputation','Regressor Imputation'],mse)]

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第28张图片

(七)用所得结果画出条形图

x_labels = ['Full data',
            'Mean Imputation',
            'Zero Imputation',
            'Regressor Imputation']
colors = ['r', 'g', 'b', 'orange']
 
plt.figure(figsize=(12, 6))  #画出画布
ax = plt.subplot(111)  #添加子图

for i in np.arange(len(mse)):  # i为0,1,2,3
    ax.barh(i, mse[i],color=colors[i], alpha=0.6, align='center') #bar为条形图,barh为横向条形图(horizon),alpha表示条的粗度
    
ax.set_title('Imputation Techniques with Boston Data')
ax.set_xlim(left=np.min(mse) * 0.9,
            right=np.max(mse) * 1.1)  #设置x轴取值范围(不希望x的刻度从0开始)
ax.set_yticks(np.arange(len(mse)))
ax.set_xlabel('MSE')
ax.set_yticklabels(x_labels)
plt.show()

【2 - 随机森林 - 原理部分】菜菜sklearn机器学习_第29张图片

这个例子有点难,第一次看有点懵,要多看几遍

你可能感兴趣的:(#,菜菜sklearn,sklearn,python)