用随机森林填补缺失值

用随机森林填补缺失值

1 引言

科研工作中采集到的数据集总会存在大量缺失值,通常直接删掉一整行效率更高,但有时候会遇到不能删掉必须填充的情况,因此本文将利用随机森林来填充波士顿数据集,并且将原始数据集,0和均值作为比较对象来验证随机森林在填充缺失值上的优越性。

2 导入的库

这里用到了sklearn中impute模块的simpleImputer函数来填充0和均值

from sklearn.datasets import load_boston
from sklearn.ensemble import RandomForestRegressor
from sklearn.impute import SimpleImputer  # 填补缺失值的类
from sklearn.model_selection import cross_val_score
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

3 数据预处理

这里我们要对波士顿数据集做一个预处理,因为它本身是完整的,所以我们需要对其进行人为的缺失操作。

3.1 引入该数据集。

dataset = load_boston()
x_full, y_full = dataset.data, dataset.target
print(x_full.shape)

由于波士顿数据集存在道德问题,所以运行的时候会出现如下警告,并且还提供了不会产生警告的代码让我们进行研究,这里我们不管它,该警告不会影响我们代码运行的。
在这里插入图片描述
我们来看标签输出结果,可以明显发现是一个连续标签,因此这里肯定做回归,要用回归器,这里我们用随机森林RandomForestRegressor模型。并且发现特征矩阵尺寸是506*13
在这里插入图片描述

3.2 产生缺失值

首先确定我们希望放入的缺失数据的比例,一共是506*13=6578个数据,在这里我们假设是50%,那总共就要有3289个数据缺失。

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

rng = np.random.RandomState(0)  # 设置随机种子
missing_rate = 0.5  # 确定缺失比例
n_missing_samples = int(np.floor(n_samples * n_features * missing_rate))

所有缺失数据会随机遍布在数据集的各行各列当中,而一个缺失的数据会需要一个行索引和一个列索引,本文将创造一个数组,包含3289个分布在0-506中间的行索引,和3289个分布在0-13之间的列索引,从而可以利用索引来为数据中的任意3289个位置赋空值,然后本文将用0,均值,随机森林来填写这些缺失值,查看回归的结果。

miss_features = rng.randint(0, n_features, n_missing_samples)  # 获取列索引
miss_samples = rng.randint(0, n_samples, n_missing_samples)  # 获取行索引
x_missing = x_full.copy()
y_missing = y_full.copy()
x_missing[miss_samples, miss_features] = np.nan
x_missing = pd.DataFrame(x_missing)

这里本文使用randint函数来创建索引数组,对于一般数据集来说,缺失值可能占数据集的10%左右,对于这种缺失值很少的情况也可以使用choice函数来创建索引数组,此时产生的索引是不重复的,并且用空值nan进行填充,缺失数据集如下:
在这里插入图片描述

4 使用0和均值填补

这里简单介绍下SimpleImputer,它一共有三个重要参数分别是missing_values, strategy和fill_value,miss_values是要告诉python数据集的缺失值形式,比如nan,-999等,strategy是确定填充值类型,比如均值,常数,中位数和众数等,当strategy='constant’常数时才会用到fill_value用来确定填充的常数值,这里本文由于填充0,因此赋值其为0。

# 使用均值进行填补
imp_mean = SimpleImputer(missing_values=np.nan, strategy='mean')  # 实例化
x_missing_mean = imp_mean.fit_transform(x_missing)  # 训练fit+导出

fit_transform接口可以同时训练和导出,然后我们来查看填充后的情况。

print(pd.DataFrame(x_missing_mean))

在这里插入图片描述
可以很明显的发现空值nan都被均值填充了。我们再用isnull函数来查看空值情况。

print(pd.DataFrame(x_missing_mean).isnull())

在这里插入图片描述

这里只要是空值则会返回False,然后对每列求和也可以发现每列都等于0,这是由于布尔值False等于0因此当某列都等于0时就可以说明该列无空值。

print(pd.DataFrame(x_missing_mean).isnull().sum())  # 有无空值,有返回True,无返回False,大于0说明有空值

在这里插入图片描述
同理我们来看用0填充的情况:

imp_0 = SimpleImputer(missing_values=np.nan, strategy='constant', fill_value=0)
x_missing_0 = imp_0.fit_transform(x_missing)
print(pd.DataFrame(x_missing_0))

在这里插入图片描述
至此我们已经填充了0和均值,接下来将利用随机森林回归来填充缺失值

5 利用随机森林回归来填充

5.1 填充思路

首先,我们需要明确一个概念,即测试集的标签不能有缺失值。因此,我们可以根据这个基本原则将接下来的新标签分成两部分。一部分是我们需要预测的空值,作为测试集的标签;另一部分则是剩下的标签值,作为训练集的标签。
此外,我们还需要划分特征矩阵。将包含空值标签的行组成的矩阵作为测试集的特征矩阵,而不包含空值的标签的行组成的矩阵作为训练集的特征矩阵。需要注意的是,我们处理的是原始特征矩阵,而原始标签将与新特征矩阵合并。
其次,当有多列包含空值的特征时,需要先将含空值最少的特征作为新标签,因为缺失数据少所需要的准确信息也少,当只剩下最后一列含空值的特征时,其余的特征都已经十分完整,因此可以很好地预测这列含空值最多的特征。
最后,我们需要找出数据集中,缺失值从小到大的特征们的顺序以及其索引,这里本文依旧采用对各列空值布尔值求和的思路进行排序。注意,如果这里用sort排序会损失索引,用argsort排序则会得到排序后的值对应索引的顺序,然后用values调取该排序。

x_missing_reg = x_missing.copy()
sort_index = np.argsort(x_missing_reg.isnull().sum(axis=0)).values

在这里插入图片描述
至此,前置工作已经做完,接下来将展示用随机森林填充缺失值的具体代码:

for i in sort_index:
    # 构建我们的新特征矩阵(没有被选中去填充的特征+原始的标签)和新标签(被选中去填充的特征)
    df = x_missing_reg
    # 新标签
    fill_c = 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 = fill_c[fill_c.notnull()]
    Ytest = fill_c[fill_c.isnull()]  # 为Xtest提供索引
    Xtrain = df_0[Ytrain.index, :]
    Xtest = df_0[Ytest.index, :]
    # 用随机森林回归来填补缺失值
    rfg = RandomForestRegressor(n_estimators=100)
    rfg = rfg.fit(Xtrain, Ytrain)
    Ypredict = rfg.predict(Xtest)  # 用predict接口将Xtest导入,得到我们的预测结果,就是我们要用来填补空值的这些值
    # x_missing_reg.iloc[Ytest.index, i] = Ypredict  # 用索引找到缺失值
    x_missing_reg.loc[x_missing_reg.iloc[:, i].isnull(), i] = Ypredict  # 用布尔值判断找到缺失值

6 四种填充方式的对比

6.1 交叉验证

目前为止,已经有了四种数据集,分别是原始数据集,填充0的数据集,填充均值的数据集以及随机森林回归填充的数据集。
接下来我们将通过交叉验证来计算各自的均方误差(mean_squared_error,简称MSE)进行比较,MSE越小说明填充效果越好。

x = [x_full, x_missing_mean, x_missing_0, x_missing_reg]

mse = []  # 越小越好

for i in x:
    estimator = RandomForestRegressor(random_state=0, n_estimators=100)  # 实例化
    scores = cross_val_score(estimator, i, y_full, scoring='neg_mean_squared_error', cv=5).mean()
    mse.append(scores*-1)

6.2 对比可视化

x = [x_full, x_missing_mean, x_missing_0, x_missing_reg]

mse = []  # 越小越好

for i in x:
    estimator = RandomForestRegressor(random_state=0, n_estimators=100)  # 实例化
    scores = cross_val_score(estimator, i, y_full, scoring='neg_mean_squared_error', cv=5).mean()
    mse.append(scores*-1)

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

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('R Square')
ax.invert_yaxis()  # 反转y轴
ax.set_yticklabels(x_labels)
plt.show()

在这里插入图片描述
可以发现用随机森林回归的MSE最小,说明填充效果很好,不过它现在比原数据集的MSE还要小,可能存在过拟合风险,需要注意。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
随机森林填补缺失值时,可以使用Pandas的DataFrame的fillna()函数结合随机森林算法填补缺失值。首先,需要导入随机森林算法的模块,如sklearn.ensemble中的RandomForestRegressor。然后,将缺失值的列作为目标列,将其他特征列作为输入特征,将已知值和缺失值分开,得到已知值的特征矩阵X_known和目标值矩阵y_known,以及缺失值的特征矩阵X_missing。接下来,使用随机森林算法来训练模型,将已知值的特征矩阵X_known和目标值矩阵y_known传入fit()函数中,得到训练好的模型。然后,使用训练好的模型来预测缺失值的目标值,将缺失值的特征矩阵X_missing传入predict()函数中,得到预测的目标值矩阵y_missing。最后,将预测的目标值矩阵y_missing填充回原始的DataFrame中的缺失值列中即可。这样就完成了使用随机森林填补缺失值的操作。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [对Pandas DataFrame缺失值的查找与填充示例讲解](https://download.csdn.net/download/weixin_38625192/12866284)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [机器学习随机森林填补缺失值和众数填补缺失值](https://blog.csdn.net/m0_58381606/article/details/126681455)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值