在真实的世界中,缺失数据是经常出现的,并可能对分析的结果造成影响。我们需要了解数据缺失的原因和数据缺失的类型,并从数据中识别缺失值,探索数据缺失的模式,进而处理缺失的数据。本文概述处理数据缺失的方法。
首先我们应该知道:数据为什么缺失?数据的缺失是我们无法避免的,可能的原因有很多种,博主总结有以下三大类:
总而言之,对于造成缺失值的原因,我们需要明确:是因为疏忽或遗漏无意而造成的,还是说故意造成的,或者说根本不存在。只有知道了它的来源,我们才能对症下药,做相应的处理。
在对缺失数据进行处理前,了解数据缺失的机制和形式是十分必要的。将数据集中不含缺失值的变量称为完全变量,数据集中含有缺失值的变量称为不完全变量。而从缺失的分布来将缺失可以分为完全随机缺失,随机缺失和完全非随机缺失。
缺失数据主要分为以下三类:
对于随机缺失和非随机缺失,直接删除记录是不合适的,上面的定义已经给出原因。随机缺失可以通过已知变量对缺失值进行估计,而非随机缺失的非随机性还没有很好的解决办法。而对于完全随机缺失可以直接删除。
Python使用NnN代表缺失值,NaN(不是一个数)代表不可能的值,符号Inf和-Inf分别代表正无穷和负无穷。
判断一个数据集是否存在缺失数据,通常从两个方面入手,
在Python环境中,可以使用DataFrame对象的isnull()方法来判断缺失值,isnull()方法返回与原数据集的shape相同的矩阵,矩阵的元素是bool类型的值,可以称作原始数据集的影子矩阵,如果影子矩阵的元素值是1,表示在原始数据集中对应该位置的值是缺失的,如果影子矩阵元素的值是0,表示在原始数据集中对应该位置的值是有效的。下面使用isnull()方法对df数据进行判断,统计输出的结果如下表所示。
# 判断各变量中是否存在缺失值 df.isnull().any(axis = 0) # 各变量中缺失值的数量 df.isnull().sum(axis = 0) # 各变量中缺失值的比例 df.isnull().sum(axis = 0)/df.shape[0]
如上结果所示,数据集df中有三个变量存在缺失值,即gender、age和edu,它们的缺失数量分别为136、100和1,927,缺失比例分别为4.53%、3.33%和64.23%。
读者可能对代码中的“axis=0”感到困惑,下面通过图表的形式来说明axis参数的用法:
假设上图为学生的考试成绩表,axis=0表示按学科分别计算每个学科的平均分,就是上图中从上到下的转换。
axis=1 表示按学生分别计算每个学生的总分,将是上图从左到右的转换。
1,判断每列是否存在缺失值
为了得到每一列的判断结果,需要any()方法(且设置方法内的axis参数为0);
# 判断各变量中是否存在缺失值 df.isnull().any(axis = 0)
2,识别数据行的缺失值分布情况
统计各变量的缺失值个数可以在isnull()的基础上使用sum()方法(同样需要设置axis参数为0);计算缺失比例就是在缺失数量的基础上除以总的样本量(shape方法返回数据集的行数和列数,[0]表示取出对应的数据行数)。代码如下:
# 缺失观测的行数 df.isnull().any(axis = 1).sum() # 缺失观测的比例 df.isnull().any(axis = 1).sum()/df.shape[0]
代码中使用了两次any“方法”,第一次用于判断每一行对应的True(即行内有缺失值)或False值(即行内没有缺失值);第二次则用于综合判断所有数据行中是否包含缺失值。同理,进一步还可以判断缺失行的具体数量和占比,
如结果所示,3000行的数据集中有2024行存在缺失值,缺失行的比例约67.47%。不管是变量角度的缺失值判断,还是数据行角度的缺失值判断,一旦发现缺失值,都需要对其作相应的处理,否则一定程度上都会影响数据分析或挖掘的准确性。
在决定如何处理缺失数据前,了解哪些变量有缺失值、数目有多少、是什么组合等信息,是非常有用的。
1,可视化缺失值的分布
查看缺失值的缺失数量以及比例
import pandas as pd # 统计缺失值数量 missing=data.isnull().sum().reset_index().rename(columns={0:‘missNum‘}) # 计算缺失比例 missing[‘missRate‘]=missing[‘missNum‘]/data.shape[0] # 按照缺失率排序显示 miss_analy=missing[missing.missRate>0].sort_values(by=‘missRate‘,ascending=False) # miss_analy 存储的是每个变量缺失情况的数据框 import matplotlib.pyplot as plt import pylab as pl fig = plt.figure(figsize=(18,6)) plt.bar(np.arange(miss_analy.shape[0]), list(miss_analy.missRate.values), align = ‘center‘ ,color=[‘red‘,‘green‘,‘yellow‘,‘steelblue‘]) plt.title(‘Histogram of missing value of variables‘) plt.xlabel(‘variables names‘) plt.ylabel(‘missing rate‘) # 添加x轴标签,并旋转90度 plt.xticks(np.arange(miss_analy.shape[0]),list(miss_analy[‘index‘])) pl.xticks(rotation=90) # 添加数值显示 for x,y in enumerate(list(miss_analy.missRate.values)): plt.text(x,y+0.12,‘{:.2%}‘.format(y),ha=‘center‘,rotation=90) plt.ylim([0,1.2]) plt.show()
这样的统计计算以及可视化基本已经看出哪些变量缺失,以及缺失比例情况,对数据即有个缺失概况。
2,用相关性探索缺失数据
变量之间有时存在很强的相关性,有时候,某一个变量缺失会导致其他变量也缺失,这就是缺失数据之间的相关性。
用指示变量代替数据集中的数据(1代表缺失,0代表存在),这样生成的矩阵有时被称作影子矩阵,求这些指示变量之间的相关性,有助于观察哪些变量经常一起缺失。
missing=data.isnull() corr_matrix = missing.corr() corr_matrix["missing_variable"].sort_values(ascending=False)
识别缺失数据的数目、分布和模式,有两个目的:分析生成缺失数据的潜在机制,评价缺失数据对回答实质性问题的影响。具体来讲,需要弄清楚以下几个问题:
回答这些问题将有助于采用合适的方法来处理缺失数据。
1,推理恢复
根据变量之间的关系来填补或恢复缺失值,通过推理,数据的恢复可能是准确无误的或近似准确的,例如,如果一个数据对象的age是20,那么该人的学历大概率是学士。
2,删除法
删除法是指将缺失值所在的行删除(前提是变量缺失的比例非常低,如5%以内),或者删除缺失值所对应的变量(前提是该变量中包含的缺失值比例非常高,比如80%左右)。把包含一个或多个缺失值的行删除,称作行删除法,或个案删除(case-wise deletion),大部分统计软件包默认采用的是行删除法。
# 删除字段,例如删除缺失率非常高的edu变量 df.drop(labels = ‘edu‘, axis = 1, inplace=True)
如果变量的缺失比例非常大,或者行缺失的比例非常小,那么使用删除法是一个不错的选择,反之,删除发将会使模型丢失大量的数据信息而得不偿失。
删除法的缺点:
这种方法在样本数据量十分大且缺失值不多的情况下非常有效,但如果样本量本身不大且缺失也不少,那么不建议使用。
3,均值替换法
均值替换法也叫均值插补,是指对存在缺失值的变量,直接利用该变量的均值、中位数或众数替换该变量的缺失值,其好处是缺失值的处理速度快,缺点是容易产生有偏估计,导致缺失值替换的准确性下降。
把数据集的属性分为定性属性和定量属性来分别进行处理:
这就意味着,对于定性数据,使用众数(mode)填补,比如一个学校的男生和女生的数量,男生500人,女生50人,那么对于其余的缺失值,我们会用人数较多的男生来填补。对于定量(定比)数据,使用平均数(mean)或中位数(median)填补,比如一个班级学生的身高特征,对于一些同学缺失的身高值就可以使用全班同学身高的平均值或中位数来填补。
一般情况下,如果特征分布为正太分布时,使用平均值效果比较好,而当分布由于异常值存在而不是正太分布的情况下,使用中位数效果比较好。
替换法对于非MCAR的数据会产生有偏向的结果,适用于缺失数据的数量较小的数据集。均值替换是在低缺失率下首选的插补方法,缺点是不能反映缺失值的变异性。
# 替换法处理缺失值 df.fillna(value = {‘gender‘: df[‘gender‘].mode()[0], # 使用性别的众数替换缺失性别 ‘age‘:df[‘age‘].mean() # 使用年龄的平均值替换缺失年龄 }, inplace = True )
缺失值的填充使用的是fillna()方法,其中value参数可以通过字典的形式对不同的变量指定不同的值。需要强调的是,如果计算某个变量的众数,一定要使用索引技术,例如代码中的[0],表示取出众数序列中的第一个(我们知道,众数是指出现频次最高的值,假设一个变量中有多个值共享最高频次,那么Python将会把这些值以序列的形式存储起来,故取出指定的众数值,必须使用索引)。
注:此方法虽然简单,但是不够精准,可能会引入噪声,或者会改变特征原有的分布。下图左为填补前的特征分布,图右为填补后的分布,明显发生了畸变。因此,如果缺失值是随机性的,那么用平均值比较适合保证无偏,否则会改变原分布。
4,随机差值
采用某种插入模式进行填充,比如取缺失值前后值的均值进行填充:
# interpolate()插值法,缺失值前后数值的均值,但是若缺失值前后也存在缺失,则不进行计算插补。 df[‘a‘] = df[‘a‘].interpolate() # 用前面的值替换, 当第一行有缺失值时,该行利用向前替换无值可取,仍缺失 df.fillna(method=‘pad‘) # 用后面的值替换,当最后一行有缺失值时,该行利用向后替换无值可取,仍缺失 df.fillna(method=‘backfill‘)#用后面的值替换
5,插补法
请阅读《机器学习 第3篇:》
参考文档:
原文:https://www.cnblogs.com/ljhdo/p/14192984.html