RandomForestRegressor&填补缺失值

RandomForestRegressor

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)

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

>>>array([-11.22504076,  -5.3945749 ,  -4.74755867, -22.54699078,
      -12.31243335, -17.18030718,  -6.94019868, -94.14567212,
      -28.541145  , -14.6250416 ])
#sklearn当中模型评估指标(打分性质)
import sklearn
sorted(sklearn.metrics.SCORERS.keys())

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

我们从现实中收集的数据,几乎不可能是完美无缺的,往往都会有一些缺失值。面对缺失值,很多人选择的方式是 直接将含有缺失值的样本删除,这是一种有效的方法,但是有时候填补缺失值会比直接丢弃样本效果更好,即便我 们其实并不知道缺失值的真实样貌。在sklearn中,我们可以使用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.shape
>>>(506, 13)
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,均值和随机森林来填写这些缺失值,然后查看回归的结果如何。

#randint(下限, 上线, n) 请在上限和下限之间取出n个整数
missing_features = rng.randint(0, n_features, n_missing_samples)     
missing_samples = rng.randint(0, n_samples, n_missing_samples)
missing_features
>>>array([12,  5,  0, ..., 11,  0,  2])

missing_samples
>>>array([150, 125,  28, ..., 132, 456, 402])

len(missing_samples)
>>>3289

我们现在采样了3289个数据,远远超过我们的样本量506,所以我们使用随机抽取的函数randint。但如果我们需要的数据量小于我们的样本量506,那我们可以采用np.random.choice来抽样,choice会随机抽取不重复的随机数,因此可以帮助我们让数据更加分散,确保数据不会集中在一些行中.

# missing_samples = rng.choice(dataset.data.shape[0],n_missing_samples,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)

X_missing

在这里插入图片描述

使用均值进行填补

from sklearn.impute import SimpleImputer

imp_mean = SimpleImputer(missing_values=np.nan, strategy='mean')     #实例化:填补缺失值,第一个参数表示缺失值是什么,此处为空值;第二个是表示用均值替换缺失值
X_missing_mean = imp_mean.fit_transform(X_missing)                   #训练fit + 导出predict -----> 特殊接口 fit_transform
pd.DataFrame(X_missing_mean).isnull().sum()
#布尔值 对应的整数,false=0,true=1,  所以加和之后,得数一定会大于1

>>>0     0
  1     0
  2     0
  3     0
  4     0
  5     0
  6     0
  7     0
  8     0
  9     0
  10    0
  11    0
  12    0
  dtype: int64


使用0进行填补

imp_0 = SimpleImputer(missing_values=np.nan, strategy="constant", fill_value=0)         #constant表示常数
X_missing_0 = imp_0.fit_transform(X_missing)

pd.DataFrame(X_missing_0)

在这里插入图片描述

使用随机森林填补缺失值

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

任何回归都是从特征矩阵中学习,然后求解连续型标签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()
sortindex = np.argsort(X_missing_reg.isnull().sum(axis=0)).values          #缺失值从少到多排序    
X_missing_reg.isnull().sum(axis=0)                                         #返回了缺失值的数量    

>>> 0     200
   1     201
   2     200
   3     203
   4     202
   5     201
   6     185
   7     197
   8     196
   9     197
   10    204
   11    214
   12    189
   dtype: int64
np.sort(X_missing_reg.isnull().sum(axis=0))                     # 直接使用sort会损失索引    

>>>array([185, 189, 196, 197, 197, 200, 200, 201, 201, 202, 203, 204, 214],dtype=int64)
np.argsort(X_missing_reg.isnull().sum(axis=0))                 #返回从小到大排序的顺序所对应的索引,第6列最少    

>>>0      6
  1     12
  2      8
  3      7
  4      9
  5      0
  6      2
  7      1
  8      5
  9      4
  10     3
  11    10
  12    11
  dtype: int64
sortindex = np.argsort(X_missing_reg.isnull().sum(axis=0)).values     
for i in sortindex:
   #构建我们的新特征矩阵(没有被选中去填充的特征+原始的标签)和新标签(被选中去填充的特征)
   
   
   df = X_missing_reg
   
   #新标签,用切片的方式取出第i列所有的行
   fillc = df.iloc[:,i]
   
   #新特征矩阵,用concat把两个连接起来,并且通过axis=1的参数,将其作为列放在最后,而非放在下面
   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()]
   #被选中的要填充的特征中(现在是我们的标签),不存在的那些值,是空值
   #我们需要的不是Y_test的值,而是其索引
   Ytest = fillc[fillc.isnull()]
   #在新的特征矩阵上,被选出来的要填充的特征的非空值所对应的记录
   Xtrain = df_0[Ytrain.index,:]
   Xtest = df_0[Ytest.index,:]
   
   #用随机森林回归来填补缺失值
   rfc = RandomForestRegressor(n_estimators=100)     #实例化
   rfc = rfc.fit(Xtrain, Ytrain)     #导入训练集进行训练
   Ypredict = rfc.predict(Xtest)     #将Xtest导入,得到我们的预测结果(回归结果),就是我们要用来填补空值的这些值
   
   #将填补好的特征返回到我们的原始的特征矩阵中
   X_missing_reg.loc[X_missing_reg.iloc[:,i].isnull(),i] = Ypredict
X_missing_reg    

在这里插入图片描述
没有缺失值了

对填充好的数据进行建模

X = [X_full,X_missing_mean,X_missing_0,X_missing_reg]      #四种构造好的数据集

mse = []

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)
   
mse     #越小越好

>>>[21.571667100368845,
   40.848037216676374,
   49.626793201980185,
   19.490047121025036]
[*zip(["X_full","X_missing_mean","X_missing_0","X_missing_reg"],mse)]     #将数据集和其得分连接起来    

>>>[('X_full', 21.571667100368845),
   ('X_missing_mean', 40.848037216676374),
   ('X_missing_0', 49.626793201980185),
   ('X_missing_reg', 19.490047121025036)]

用所得结果画出条形图

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)):
   ax.barh(i, mse[i],color=colors[i], alpha=0.6, align='center')              #barh 是横着的条形图

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)))  #设置y的刻度
ax.set_xlabel('MSE') 
ax.invert_yaxis()
ax.set_yticklabels(x_labels)        #用x_labels列表的元素作为y的命名
plt.show()

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_45044758/article/details/107578725