深度学习之“缺失数据处理”

缺失值检测

缺失数据就是我们没有的数据。如果数据集是由向量表示的特征组成,那么缺失值可能表现为某些样本的一个或多个特征因为某些原因而没有测量的值。通常情况下,缺失值由特殊的编码方式。如果正常值都是正数,那么缺失值可能被标记为-1;如果正常值是字符串,那么缺失值可能是空的字符串;如果正常值是浮点数,那么缺失值可能是NaN。

在python中,我们能够通过使用np.isnan来判断数据是否为NaN:

bash 复制代码
>>> import numpy as np
>>> a = np.arange(10, dtype="float64")
>>> a[3] = np.nan
>>> np.isnan(a[3])
True
>>> a[3] == np.nan
False
>>> a[3] is np.nan
False
>>> np.isnan(a)
array([False, False, False,  True, False, False, False, False, False,
       False])

可以看到,只能用np.isnan来判断,"=="和"is"进行比较是无效的。

缺失值处理

假定我们已经知道数据中存在缺失值,那么我们就需要寻找一些手段来对其进行处理,从而避免对模型训练产生负面影响。

首先我们先生成一组数据,其中包含1000个样本,且每个样本都具有四维特征:

bash 复制代码
>>> import numpy as np
>>> N=1000
>>> np.random.seed(100)
>>> x = np.zeros((N,4))
>>> x[:,0] = 5*np.random.random(N)
>>> x[:,1] = np.random.normal(10,1,size=N)
>>> x[:,2] = 3*np.random.beta(5,2,N)
>>> x[:,3] = 0.3*np.random.lognormal(size=N)

其中我们固定随机种子,从而确保结果的可复现性,并且1-4维的数据分别来自均匀分布、正态分布、贝塔分布和对数正态分布。之后我们向其中随机添加5%的缺失值:

bash 复制代码
>>> i = np.random.randint(0,N,size=int(0.05*N))
>>> x[i,0] = np.nan
>>> i = np.random.randint(0,N,size=int(0.05*N))
>>> x[i,1] = np.nan
>>> i = np.random.randint(0,N,size=int(0.05*N))
>>> x[i,2] = np.nan
>>> i = np.random.randint(0,N,size=int(0.05*N))
>>> x[i,3] = np.nan

那么我们应该如何来处理这些缺失值呢?

直接丢弃

如果我们拥有的数据集较为庞大,而缺失值的占比很小,且分布较为均匀,那么直接丢弃这些缺失值也是可以的。但是如果缺失值与某个类别存在相关性,直接丢掉这些样本可能在某种程度上会导致数据集有偏,进而影响模型的准确性。

均值/中位数填充

我们还可以参考剔除缺失值后数据的分布形态,选择使用数据均值或者中位数来对缺失值进行填充。我们首先剔除数据中的缺失值,并使用matplotlib.pyplot中的boxplot函数来查看剔除缺失值后数据的箱形图:

python 复制代码
import matplotlib.pyplot as plt
# 剔除缺失值
def remove_nan_columnwise(data):
    """从每一列中剔除NaN值"""
    return [data[~np.isnan(data[:, col]), col] for col in range(data.shape[1])]

# 应用函数到数据
cleaned_data = remove_nan_columnwise(x)

# 绘制箱形图
plt.figure(figsize=(10, 6))
plt.boxplot(cleaned_data, labels=['Column 1', 'Column 2', 'Column 3', 'Column 4'])
plt.title('Box Plot of Data After Removing Missing Values')
plt.ylabel('Value')
plt.show()

从图中可以看出,第1、2维的数据偏差较小,且箱形框较为对称;第3维的数据偏上,第4维的数据偏下。因此我们使用均值来替代第1、2维的缺失数据,使用中位数来替换第3、4维的数据。

python 复制代码
i = np.where(np.isnan(x[:,0]) == False)
m = np.mean(x[i,0])
i = np.where(np.isnan(x[:,0]) == True)
x[i,0] = m

i = np.where(np.isnan(x[:,1]) == False)
m = np.mean(x[i,1])
i = np.where(np.isnan(x[:,1]) == True)
x[i,1] = m

i = np.where(np.isnan(x[:,2]) == False)
m = np.median(x[i,2])
i = np.where(np.isnan(x[:,2]) == True)
x[i,2] = m

i = np.where(np.isnan(x[:,3]) == False)
m = np.median(x[i,3])
i = np.where(np.isnan(x[:,3]) == True)
x[i,3] = m

关于何时用中位数替代缺失值,何时用均值替代缺失值,给出的参考如下:

使用中位数填充的情况

  1. 当数据是偏斜分布或存在异常值时:如果数据不是正态分布,而是偏向一侧(即有长尾),或者存在极端值(outliers),那么使用中位数可能是更好的选择。因为中位数不受极值影响,可以更好地代表中心趋势。
  2. 对于非正态分布的数据:如果变量不符合正态分布,中位数可能是一个更稳健的选择,因为它更能反映大多数观测值的集中位置。
  3. 对于有序分类数据:当处理有序分类变量(例如,教育水平、满意度评分等)时,中位数也可能是更合适的选择。
  4. 当需要保持数据的原始分布特征时:在某些情况下,使用中位数可以帮助保持数据集的原有分布特性,尤其是在存在明显偏斜的情况下。

使用平均值填充的情况

  1. 当数据接近正态分布且没有显著异常值时:如果数据大致呈正态分布,并且不存在明显的异常值,那么使用平均值填充可能是合适的,因为它会考虑所有观测值。
  2. 对于数值型数据:平均值通常用于数值型数据,尤其是那些期望值具有实际意义的变量。
  3. 当想要最小化总平方误差时:平均值是使得预测误差平方和最小化的估计量,因此在某些统计分析中,它可能是首选。
  4. 对于回归分析中的连续变量:在进行回归分析时,如果变量是连续的,并且你认为缺失值应该反映总体的"平均水平",那么平均值可能是一个合理的选择。
相关推荐
远洋录12 分钟前
构建一个研发助手Agent:提升开发效率的实践
人工智能·ai·ai agent
流形填表27 分钟前
用FormLinker实现自动调整数据格式,批量导入微软表单
python·microsoft·flask
goomind27 分钟前
opencv实现边缘模板匹配
c++·人工智能·opencv·计算机视觉·模板匹配
稚辉君.MCA_P8_Java43 分钟前
SpringAI 人工智能
大数据·linux·人工智能·分布式·spring
pps-key44 分钟前
汽车自动驾驶AI
人工智能·自动驾驶·汽车
一水鉴天1 小时前
为AI聊天工具添加一个知识系统 之73 详细设计之14 正则表达式 之1
网络·人工智能
qwe3526331 小时前
自定义数据集 使用pytorch框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测,对预测结果计算精确度和召回率及F1分数
python
广药门徒2 小时前
用Python替代OpenMV IDE显示openmv USB 图像
开发语言·ide·python
weixin_307779132 小时前
自然语言生成(NLG)算法模型评估方案的硬件配置、系统架构设计、软件技术栈、实现流程和关键代码
人工智能·算法·自然语言处理·系统架构