《scikit-learn》随机森林回归填补缺失值

在清洗数据的阶段,我们面对缺失值有三种方式
1:直接将少量具有缺失值的样本删除。
2:将大量缺失值的特征删除。
3:中等含有缺失值的特征进行填补。

在scikit-learn中,有一个专门填充的类,专门将均值,中值,或其他数值填充,比如还有0值填充,随机森林回归填充,来分别验证拟合状况,来找出此数据集最佳的缺失值填补方式。

假如我们还是使用回归数据来做测试,使用boston房价数据。
第一步:加载数据

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from sklearn.datasets import load_boston
from sklearn.ensemble import RandomForestRegressor
from sklearn.impute import SimpleImputer  # 用来填补缺失值
from sklearn.model_selection import cross_val_score

# ====1:加载数据
boston = load_boston()

这里不展开介绍了,简单说是506个样本,13个特征。

第二步:人为地构造一些缺失值,

# ====2:人为地,随机地,让一些数据缺失掉
x_src = boston.data  # 原始特征矩阵数据
y_src = boston.target  # 原始目标数据

n_samples = x_src.shape[0]  # 样本个数
n_features = x_src.shape[1]  # 特征个数

rnd = np.random.RandomState(1)  # 定义一个随机数种子
n_samples_missing = int(n_samples * n_features * 0.3)  # 大概有30%的数据将要被我们擦除掉。计算出要擦除的个数
print('we will drop {} values.'.format(n_samples_missing))

missing_samples_list = rnd.randint(0, n_samples, n_samples_missing)  # 从0 ~ n_samples 随机采样出n_samples_missing个整数
missing_features_list = rnd.randint(0, n_features, n_samples_missing)  # 从0 ~ n_features 随机采样出n_samples_missing个整数

x_src[missing_samples_list, missing_features_list] = np.nan  # 现在我们就把一些随机的位置给抹去了,俩列表的长度必须是一致的
x_missing = pd.DataFrame(x_src)
print(x_missing.head())  # 至此,我们人为丢弃一些数据,造成缺失数据就完成了。

我们把特征矩阵的大概30%的数据置为空值,来模拟我们的缺失值。大约有1973个值要被置为空。
随机抽出这些值,使用随机数产生器来帮我寻找。

第三步:用不同的策略来生生填充后的特征矩阵,这里用到了SimpleImputer这个类
1:使用特征均值来填充

# 填充方法一:使用均值填充全部的缺失值
imp_mean = SimpleImputer(missing_values=np.nan, strategy='mean')  # 实例化一个填充均值的处理器
x_missing_mean = imp_mean.fit_transform(x_missing)  # 使用fit_transform来实现填充
print('fill mean.....')
print(pd.DataFrame(x_missing_mean).head())

2:使用特征的中值填充

# 填充方法二:使用中值填充全部的缺失值
imp_median = SimpleImputer(missing_values=np.nan, strategy='median')  # 实例化一个填充中值的处理器
x_missing_median = imp_median.fit_transform(x_missing)  # 使用fit_transform来实现填充
print('fill median.....')
print(pd.DataFrame(x_missing_median).head())

3:使用常数0来填充

# 填充方法三:使用0填充全部的缺失值
imp_zero = SimpleImputer(missing_values=np.nan, strategy='constant', fill_value=0)  # 实例化一个填充0的处理器
x_missing_zero = imp_zero.fit_transform(x_missing)  # 使用fit_transform来实现填充
print('fill zero.....')
print(pd.DataFrame(x_missing_zero).head())

4:使用模型学习出缺失值
这块也是我们今天学习的关键,如何学习出这么多缺失值呢?
我们想一想贝叶斯的思想,先验概率和后验概率,也就是特征和目标之间是可以互换的,目标也能当做是特征,特征也可以当做是目标。举个例子:我们可以用“地区”,“交通”,“学区数量”来预测“房价”,反过来我们也可以用“房价”,“交通”,“学区数量”来预测“地区”啊。

具体就是,数据集X有N个特征,当我们只有一个特征F有缺失的时候,我们就把目标Y和F进行互换,形成新的特征矩阵,F就是新的目标,Y此时就是作为特征了。
新目标F中不缺失的数据,就是y_train。
y_train对应的特征矩阵,就是x_train。
新目标F中缺失的数据,就是y_test。
y_ test对应的特征矩阵,就是x_test。

我们可以根据x_train,y_train,训练出一个回归/分类模型,再对x_test进行predict预测,得到的结果y_predict就是我们学习到的y_test,替换特征F一整列中缺失的值即可。

那如果存在多列有缺失值的?不着急,一个个慢慢来,我们按照缺失值的数量多少从少到多排个序,每一个特征都进行这样的互换、学习、替换的过程。

从少到多是因为,缺失值越少,信息熵越低,越容易处理,准确度也是越高。

需要注意的是,每次学习某个单个特征之前呢,先把其他特征临时赋值,比如是常数值,平均值,中值等,保证只有唯一一个特征是含有缺失值。

# 填充方法四:使用随机森林回归,用学习的方式来填充,逐步分特征来填充。
x_missing_reg = x_missing
print('before learning.....')
print(x_missing_reg.head())
print(x_missing_reg.isnull().sum(axis=0))

# 计算各个特征的缺失值的个数,并且按照从少到多的顺序来一个个学习。从少到多,所需要的信息量也是从简单到难,一步步迭代式。
# argsort 返回从小大值的下标,这才是我们需要的咧。
sorted_indexes = np.argsort(x_missing_reg.isnull().sum(axis=0)).values  # True是1,FALSE是0
print('sorted_indexes:', sorted_indexes)
for i in sorted_indexes:
    # 构建新的特征矩阵和新的目标,也就是将第i个特征作为新的目标,原来的目标作为特征。
    feature_i = x_missing_reg.iloc[:, i]
    tmp_df = pd.concat([x_missing_reg.iloc[:, x_missing_reg.columns != i], pd.DataFrame(y_src)], axis=1)

    # 在新组装的特征矩阵里面,将所有的的缺失值进行填充平均值 处理
    imp_mean = SimpleImputer(missing_values=np.nan, strategy='mean')  # 实例化一个填充均值的处理器
    tmp_df_mean = imp_mean.fit_transform(tmp_df)  # 使用fit_transform来实现填充,返回numpy.ndarray类型

    # 找出我们的训练集和测试集
    y_train = feature_i[feature_i.notnull()]  # 新的目标中,非空的作为y_train
    y_test = feature_i[feature_i.isnull()]   # 新的目标中,为空的作为y_test,本身不需要,而是需要知道其所在的索引。
    x_train = tmp_df_mean[y_train.index, :]  # .index可以获得下标号,新的目标非空值对应的特征
    x_test = tmp_df_mean[y_test.index, :]  # 新的目标空值对应的特征

    # 建立随机森林回归树进行训练
    rfc = RandomForestRegressor(n_estimators=100)
    rfc = rfc.fit(x_train, y_train)
    y_predict = rfc.predict(x_test)

    # 将学习到了Y赋值给原始数据。
    x_missing_reg.loc[x_missing_reg.iloc[:, i].isnull(), i] = y_predict

print('after learning.....')
print(x_missing_reg.head())
print(x_missing_reg.isnull().sum(axis=0))  # 计算每个特征下还是 nan 的数量

第四步:对多种数据集进行多次交叉验证测试打分,比较优劣。

# ====4:进数据准备就绪,来分别看看效果。不同的填充的数据集在相同的随机森林回归下,预测的效果。
datas = [x_src, x_missing, x_missing_mean, x_missing_median, x_missing_zero, x_missing_reg]
label = ['x_src', 'no any fill', 'x_missing_mean', 'x_missing_median', 'x_missing_zero', 'x_missing_reg']
res_cmp = []
for x in datas:  # 遍历每个已经填充了的数据集
    scores_rfc = []
    for c in range(1, 11):  # 对于每一填充数据集,重复执行10次交叉验证,看看效果。
        rfc = RandomForestRegressor(criterion='mse', n_estimators=10)
        score_tfc = cross_val_score(rfc, x, y_src, cv=10, scoring='neg_mean_squared_error').mean()
        scores_rfc.append(score_tfc)
    res_cmp.append(scores_rfc)

# 画图画出来展示下
print(res_cmp)
for i in range(len(label)):
    plt.plot(range(1, 11), res_cmp[i], label=label[i])
plt.legend()  # 显示图例
plt.show()

结果如下:
在这里插入图片描述
在这里插入图片描述

结论是:
说明采取不同的缺失值填充措施效果是有差距的,采取学习后的填充值,是最接近于原始数据的,效果极好,其他地“一刀切”式的填充会带来不怎么好的结果。

奇怪的是,没有进行任何缺失值填充的数据集也会表现的很好,跟原始数据还有学习填充的数据不分上下,看来随机森林内部应该是有一定的很好的缺失值填充处理策略了。

最后,之所以要花大力气学习,这里还有一些常用的数据操作的方法,也算是学习python了。

  • 7
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值