【Python数据分析基础】: 数据缺失值处理

做者:xiaoyuphp

微信公众号:Python数据科学html

知乎:python数据分析师python


圣人曾说过:数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。算法

再好的模型,若是没有好的数据和特征质量,那训练出来的效果也不会有所提升。数据质量对于数据分析而言是相当重要的,有时候它的意义会在某种程度上会赛过模型算法。bash

本篇开始分享如何使用Python进行数据分析,主要侧重介绍一些分析的方法和技巧,而对于pandas和numpy等Pyhon计算包的使用会在问题中说起,但不详细介绍。本篇咱们来讲说面对数据的缺失值,咱们该如何处理。文末有博主总结的思惟导图。微信

1 数据缺失的缘由

首先咱们应该知道:数据为何缺失?数据的缺失是咱们没法避免的,可能的缘由有不少种,博主总结有如下三大类:dom

  • 无心的:信息被遗漏,好比因为工做人员的疏忽,忘记而缺失;或者因为数据采集器等故障等缘由形成的缺失,好比系统实时性要求较高的时候,机器来不及判断和决策而形成缺失;
  • 有意的:有些数据集在特征描述中会规定将缺失值也做为一种特征值,这时候缺失值就能够看做是一种特殊的特征值;
  • 不存在:有些特征属性根本就是不存在的,好比一个未婚者的配偶名字就无法填写,再如一个孩子的收入情况也没法填写;

总而言之,对于形成缺失值的缘由,咱们须要明确:是由于疏忽或遗漏无心而形成的,仍是说故意形成的,或者说根本不存在。只有知道了它的来源,咱们才能对症下药,作相应的处理。机器学习

2 数据缺失的类型

在对缺失数据进行处理前,了解数据缺失的机制和形式是十分必要的。将数据集中不含缺失值的变量称为彻底变量,数据集中含有缺失值的变量称为不彻底变量。而从缺失的分布来将缺失能够分为彻底随机缺失,随机缺失和彻底非随机缺失。函数

  • 彻底随机缺失(missing completely at random,MCAR):指的是数据的缺失是彻底随机的,不依赖于任何不彻底变量或彻底变量,不影响样本的无偏性,如家庭地址缺失;
  • 随机缺失(missing at random,MAR):指的是数据的缺失不是彻底随机的,即该类数据的缺失依赖于其余彻底变量,如财务数据缺失状况与企业的大小有关;
  • 非随机缺失(missing not at random,MNAR):指的是数据的缺失与不彻底变量自身的取值有关,如高收入人群不原意提供家庭收入;

对于随机缺失和非随机缺失,直接删除记录是不合适的,缘由上面已经给出。随机缺失能够经过已知变量对缺失值进行估计,而非随机缺失的非随机性尚未很好的解决办法。学习

3 数据缺失的处理方法

重点来了,对于各类类型数据的缺失,咱们到底要如何处理呢?如下是处理缺失值的四种方法:删除记录,数据填补,和不处理

1. 删除记录

优势:

  • 最简单粗暴;

缺点:

  • 牺牲了大量的数据,经过减小历史数据换取完整的信息,这样可能丢失了不少隐藏的重要信息;
  • 当缺失数据比例较大时,特别是缺失数据非随机分布时,直接删除可能会致使数据发生偏离,好比本来的正态分布变为非正太;

这种方法在样本数据量十分大且缺失值很少的状况下很是有效,但若是样本量自己不大且缺失也很多,那么不建议使用。

Python中的使用: 可使用 pandasdropna 来直接删除有缺失值的特征。

#删除数据表中含有空值的行
df.dropna(how='any')
复制代码

2. 数据填补

对缺失值的插补大致可分为两种:替换缺失值,拟合缺失值,虚拟变量。替换是经过数据中非缺失数据的类似性来填补,其核心思想是发现相同群体的共同特征,拟合是经过其余特征建模来填补,虚拟变量是衍生的新变量代替缺失值。

替换缺失值

  • 均值插补:

对于定类数据:使用 众数(mode)填补,好比一个学校的男生和女生的数量,男生500人,女生50人,那么对于其他的缺失值咱们会用人数较多的男生来填补。

对于定量(定比)数据:使用平均数(mean)或中位数(median)填补,好比一个班级学生的身高特征,对于一些同窗缺失的身高值就可使用全班同窗身高的平均值或中位数来填补。通常若是特征分布为正太分布时,使用平均值效果比较好,而当分布因为异常值存在而不是正太分布的状况下,使用中位数效果比较好。

注:此方法虽然简单,可是不够精准,可能会引入噪声,或者会改变特征原有的分布。 下图左为填补前的特征分布,图右为填补后的分布,明显发生了畸变。所以,若是缺失值是随机性的,那么用平均值比较适合保证无偏,不然会改变原分布。

Python中的使用:
#使用price均值对NA进行填充
df['price'].fillna(df['price'].mean())
df['price'].fillna(df['price'].median())
复制代码
  • 热卡填补(Hot deck imputation):

热卡填充法是在完整数据中找到一个与它最类似的对象,而后用这个类似对象的值来进行填充。一般会找到超出一个的类似对象,在全部匹配对象中没有最好的,而是从中随机的挑选一个做为填充值。这个问题关键是不一样的问题可能会选用不一样的标准来对类似进行断定,以及如何制定这个断定标准。该方法概念上很简单,且利用了数据间的关系来进行空值估计,但缺点在于难以定义类似标准,主观因素较多。

  • K最近距离邻法(K-means clustering)

另一种方法就是利用无监督机器学习的聚类方法。经过K均值的聚类方法将全部样本进行聚类划分,而后再经过划分的种类的均值对各自类中的缺失值进行填补。归其本质仍是经过找类似来填补缺失值。

注:缺失值填补的准确性就要看聚类结果的好坏了,而聚类结果的可变性很大,一般与初始选择点有关,而且在下图中可看到单独的每一类中特征值也有很大的差异,所以使用时要慎重。

拟合缺失值

拟合就是利用其它变量作模型的输入进行缺失变量的预测,与咱们正常建模的方法同样,只是目标变量变为了缺失值。

注:若是其它特征变量与缺失变量无关,则预测的结果毫无心义。若是预测结果至关准确,则又说明这个变量彻底没有必要进行预测,由于这必然是与特征变量间存在重复信息。通常状况下,会介于二者之间效果为最好,若强行填补缺失值以后引入了自相关,这会给后续分析形成障碍。

利用模型预测缺失变量的方法有不少,这里仅简单介绍几种。

  • 回归预测:

如咱们以前提到的房价预测项目同样数据分析实战—北京二手房房价分析(建模篇),基于完整的数据集,创建回归方程。对于有缺失值的特征值,将已知特征值代入模型来估计未知特征值,以此估计值来进行填充,如下图为例。固然关于回归的方法有不少,这里就不详细介绍了。

缺失值是连续的,即定量的类型,才可使用回归来预测。

  • 极大似然估计(Maximum likelyhood):

在缺失类型为随机缺失的条件下,假设模型对于完整的样本是正确的,那么经过观测数据的边际分布能够对未知参数进行极大似然估计(Little and Rubin)。这种方法也被称为忽略缺失值的极大似然估计,对于极大似然的参数估计实际中常采用的计算方法是指望值最大化(Expectation Maximization,EM)。该方法比删除个案和单值插补更有吸引力,它一个重要前提:适用于大样本。有效样本的数量足够以保证ML估计值是渐近无偏的并服从正态分布。可是这种方法可能会陷入局部极值,收敛速度也不是很快,而且计算很复杂,且仅限于线性模型。

  • 多重插补(Mutiple imputation):

多值插补的思想来源于贝叶斯估计,认为待插补的值是随机的,它的值来自于已观测到的值。具体实践上一般是估计出待插补的值,而后再加上不一样的噪声,造成多组可选插补值。根据某种选择依据,选取最合适的插补值。

咱们看到,以上提出的拟合和替换方法都是单一的插补方法,而多重插补弥补了单一插补的缺陷,它并无试图去经过模拟值去估计每一个缺失值,而是提出缺失数据值的一个随即样本(这些样本能够是不一样的模型拟合结果的组合)。这种程序的实施恰当地反映了因为缺失值引发的不肯定性,使得统计推断有效。多重插补推断能够分为如下3个步骤:

  • 为每一个缺失值产生一套可能的插补值,这些值反映了无响应模型的不肯定性;
  • 每一个插补数据集合都用针对完整数据集的统计方法进行统计分析;
  • 对来自各个插补数据集的结果,根据评分函数进行选择,产生最终的插补值;

根据数据缺失机制、模式以及变量类型,可分别采用回归、预测均数匹配( predictive mean matching, PMM )、趋势得分( propensity score, PS )、Logistic回归、判别分析以及马尔可夫链蒙特卡罗( Markov Chain Monte Carlo, MCMC) 等不一样的方法进行填补。

假设一组数据,包括三个变量Y1,Y2,Y3,它们的联合分布为正态分布,将这组数据处理成三组,A组保持原始数据,B组仅缺失Y3,C组缺失Y1和Y2。在多值插补时,对A组将不进行任何处理,对B组产生Y3的一组估计值(做Y3关于Y1,Y2的回归),对C组做产生Y1和Y2的一组成对估计值(做Y1,Y2关于Y3的回归)。

当用多值插补时,对A组将不进行处理,对B、C组将完整的样本随机抽取造成为m组(m为可选择的m组插补值),每组个案数只要可以有效估计参数就能够了。对存在缺失值的属性的分布做出估计,而后基于这m组观测值,对于这m组样本分别产生关于参数的m组估计值,给出相应的预测,这时采用的估计方法为极大似然法,在计算机中具体的实现算法为指望最大化法(EM)。对B组估计出一组Y3的值,对C将利用Y1,Y2,Y3它们的联合分布为正态分布这一前提,估计出一组(Y1,Y2)。

上例中假定了Y1,Y2,Y3的联合分布为正态分布。这个假设是人为的,可是已经经过验证(Graham和Schafer于1999),非正态联合分布的变量,在这个假定下仍然能够估计到很接近真实值的结果。

注:使用多重插补要求数据缺失值为随机性缺失,通常重复次数20-50次精准度很高,可是计算也很复杂,须要大量计算。

  • 随机森林:

另外一种比较经常使用的拟合方法就是随机森林,这也是Kaggle竞赛中大佬们常用的一个办法,具体实现方式与正常同样,只是将缺失值做为目标变量便可。如下**知识星球项目(一)**中一段代码,仅供参考。

def set_missing_ages(df):

    # 把已有的数值型特征取出来丢进Random Forest Regressor中
    age_df = df[['Age','Fare', 'Parch', 'SibSp', 'Pclass']]

    # 乘客分红已知年龄和未知年龄两部分
    known_age = age_df[age_df.Age.notnull()].as_matrix()
    unknown_age = age_df[age_df.Age.isnull()].as_matrix()

    # y即目标年龄
    y = known_age[:, 0]

    # X即特征属性值
    X = known_age[:, 1:]

    # fit到RandomForestRegressor之中
    rfr = RandomForestRegressor(random_state=0, n_estimators=2000, n_jobs=-1)
    rfr.fit(X, y)

    # 用获得的模型进行未知年龄结果预测
    predictedAges = rfr.predict(unknown_age[:, 1:])
# print predictedAges
    # 用获得的预测结果填补原缺失数据
    df.loc[ (df.Age.isnull()), 'Age' ] = predictedAges 

    return df, rfr
复制代码
  • 虚拟变量

虚拟变量其实就是缺失值的一种衍生变量。具体作法是经过判断特征值是否有缺失值来定义一个新的二分类变量。好比,特征为A含有缺失值,咱们衍生出一个新的特征B,若是A中特征值有缺失,那么相应的B中的值为1,若是A中特征值没有缺失,那么相应的B中的值为0。

下面是知识星球项目(一)中的一段程序:

data_train['CabinCat'] = data_train['Cabin'].copy()
data_train.loc[ (data_train.CabinCat.notnull()), 'CabinCat' ] = "No"
data_train.loc[ (data_train.CabinCat.isnull()), 'CabinCat' ] = "Yes"

fig, ax = plt.subplots(figsize=(10,5))
sns.countplot(x='CabinCat', hue='Survived',data=data_train)
plt.show()
复制代码

下面能够经过一行代码清楚看到衍生的虚拟变量。

data_train[['Cabin','CabinCat']].head(10)
复制代码

3. 不处理

补齐处理只是将未知值补以咱们的主观估计值,不必定彻底符合客观事实,在对不完备信息进行补齐处理的同时,咱们或多或少地改变了原始的信息系统。并且,对空值不正确的填充每每将新的噪声引入数据中,使挖掘任务产生错误的结果。所以,在许多状况下,咱们仍是但愿在保持原始信息不发生变化的前提下对信息系统进行处理。

在实际应用中,一些模型没法应对具备缺失值的数据,所以要对缺失值进行处理。然而还有一些模型自己就能够应对具备缺失值的数据,此时无需对数据进行处理,好比Xgboost,rfr等高级模型。

4 总结

总而言之,大部分数据挖掘的预处理都会使用比较方便的方法来处理缺失值,好比均值法,可是效果上并必定好,所以仍是须要根据不一样的须要选择合适的方法,并无一个解决全部问题的万能方法。具体的方法采用还须要考虑多个方面的:

  • 数据缺失的缘由;
  • 数据缺失值类型;
  • 样本的数据量;
  • 数据缺失值随机性等;

关于数据缺失值得思惟导图:

若是你们有任何好的其余方法,欢迎补充。

参考:

http://www.restore.ac.uk/PEAS/imputation.php

https://blog.csdn.net/lujiandong1/article/details/52654703

http://blog.sina.com.cn/s/blog_4b0f1da60101d8yb.html

https://www.cnblogs.com/Acceptyly/p/3985687.html

关注微信公众号: Python数据科学,发现更多精彩内容。
相关文章
相关标签/搜索