缺失值可分为两类:一类是这个值实际存在但是没有被观测到,例如客户的性别;另一类是这个值实际就不存在,例如,在调查顾客购买的洗发液品牌时,如果某位顾客根本没有购买任何洗发液,那么这位顾客购买的洗发液品牌缺失。如何处理缺失值是一个很复杂的课题,有兴趣的读者可以参阅这方面的专著。
缺失值的产生有三种机制:
1.完全随机缺失(MissingCompletelyatRandom)
某个变量是否缺失与它自身的值无关,也与其他任何变量的值无关。例如,由于测量设备出故障导致某些值缺失。
2.随机缺失(MissingatRandom)
在控制了其他变量已观测到的值后,某个变量是否缺失与它自身的值无关。例如,人们是否透露收入可能与性别、教育程度、职业等因素有关系。
如果这些因素都观测到了,而且尽管收入缺失的比例在不同性别、教育程度、职业的人群之间有差异,但是在每一类人群内收入是否缺失与收入本身的值无关,那么收入就是随机缺失的。
3.非随机缺失(MissingNotatRandom)
即使控制了其他变量已观测到的值,某个变量是否缺失仍然与它自身的值有关。例如,在控制了性别、教育程度、职业等已观测因素之后,如果收入是否缺失还依赖于收入本身的值,那么收入就是非随机缺失的。
常见的数据缺失填充方式分为很多种,比如删除法、均值法、回归法、KNN、MICE、EM等等。R语言包中在此方面比较全面,python稍差。
python目前已有的两种常见的包,第一个是impyute,第二个是fancyimpute。比如fancyimpute中集成了很多方式,包括均值、众数、频数填充,KNN填充、MCMC填充等。
data = pd.read_csv(path,encoding='gbk')
data = data.fillna(-1)
用单一变量的均值/中位数/众数/二分之一最小值/零值进行补值,这种方法会导致数据分布的偏移,方差偏小,PCA上会看到一条补值导致的直线等问题。
这种方法仅在缺失数据集满足正态分布的情况下可以达到比较好的效果,而在现实应用中,往往连对数据具一定的先验知识都很难做到,而现实数据往往又并不是简单的正态分布,因此这一方法不可避免的将带来数据的各种统计参数的扭曲。
所谓的插值法就是通过两点(x0,y0),(x1,y1)估计中间点的值,假设y=f(x)是一条直线,通过已知的两点来计算函数f(x),然后只要知道x就能求出y,以此方法来估计缺失值。当然我们也可以假设f(x)不是直线,而是其他函数。
data = pd.read_csv(path,encoding='gbk')
for f in data: # 插值法填充
data[f] = data[f].interpolate()
data.dropna(inplace=True)
interpolate函数默认采用线性插值,即假设函数是直线形式,缺失值用前一个值和后一个值的平均数填充。
还可以根据数字来进行插值,用到参数method=‘values’,此时索引的数值实际上就是用于估计y的x值。
如果index是时间,我们还可以用method=time来插值。不过当dataframe是多重索引(multiIndex)时,只能用线性插值。
此外还可以通过参数设定采用多项式插值填充等方式。
参考:
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.interpolate.html
https://jingyan.baidu.com/article/a501d80cf7c9c3ec620f5e5a.html
KNN预测的步骤是选择出其他不存在缺失值的列,同时去除掉需要预测缺失值的列存在缺失值的行,然后计算距离。
如果缺失值是离散的,使用K近邻分类器,投票选出K个邻居中最多的类别进行填补;如果为连续变量,则用K近邻回归器,拿K个邻居中该变量的平均值填补。
这里使用的是fancyimpute库,安装的时候需要visual C++环境。
from fancyimpute import KNN
data = pd.read_csv(path,encoding='gbk')
data = pd.DataFrame(KNN(k=6).fit_transform(data))
data.columns = ['sex','age','label'] # fancyimpute填补缺失值时会自动删除列名
注意fancyimpute的KNN填补会自动去除DataFrame数据的列名,所以如果后续操作对列名有要求,需要重新添加列名。
见本人的另一篇博文。
参考网址:
面对有大量缺失值的数据应该怎样处理比较合理? - 晔无殊的回答 - 知乎
MetImp 1.2 (开源的的缺失值补值软件)
缺失值处理方法综述
缺失值的产生机制
缺失值的处理(非常好)