数据分析之 缺失值分析

  • 查看缺失情况:

    dataframe.isnull() 

  元素级别的判断,把对应的所有元素的位置都列出来,元素为空或者NA就显示True,否则就是False

    dataframe.isnull().any()

  列级别的判断,只要该列有为空或者NA的元素,就为True,否则False

    missing = dataframe.columns[ dataframe.isnull().any() ].tolist()  

  将为空或者NA的列找出来

    dataframe [ missing ].isnull().sum()

  将列中为空或者NA的个数统计出来

    len(data["feature"] [ pd.isnull(data["feature"]) ]) / len(data))

  缺失值比例
  • 缺失值处理方法:
    总图:在这里插入图片描述

  • 处理方式

    • 直接删除:
DataFrame.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)
功能:根据各标签的值中是否存在缺失数据对轴标签进行过滤,可通过阈值调节对缺失值的容忍度
参数:axis : {0 or ‘index’, 1 or ‘columns’},或 tuple/list 
   how : {‘any’, ‘all’}
     any : 如果存在任何NA值,则放弃该标签
     all :    如果所有的值都为NA值,则放弃该标签
   thresh : int, 默认值 None
      int value :要求每排至少N个非NA值  
   subset : 类似数组
   inplace : boolean, 默认值 False
      如果为True,则进行操作并返回None。
返回:被删除的DataFrame
	** - 常见删除方法:**

    new_drop = dataframe.dropna ( axis=0,subset=["Age","Sex"] ) 【在子集中有缺失值,按行删除】
    new_drop = dataframe.dropna ( axis=1)  【将dataframe中含有缺失值的所有列删除】

  • 插补法
    • data.Age.fillna(data.Age.mean(),inplace=True) 均值插补法 正态分布
    • df[‘price’].fillna(df[‘price’].median()) 中值法 偏长尾分布
    • 最近插补法
      dataframe [‘age’].fillna(method=‘pad’) # 使用前一个数值替代空值或者NA,就是NA前面最近的非空数值替换
      dataframe [‘age’].fillna(method=‘bfill’,limit=1) # 使用后一个数值替代空值或者NA,limit=1就是限制如果几个连续的空值,只能最近的一个空值可以被填充。
  • 回归插补法:
    选择若干个预测缺失值的自变量,建立回归方程估计缺失值即用缺失数据的条件期望值对缺失值进行替换。
    弊端:无偏估计,容易忽略其他未知性质的属性,而且这一现象当数据缺失信息越多越明显。第二很多时候这种假设的线性关系并不存在。
  • 拉格朗日插值法:
    维基百科拉个朗日插值法描述 很清楚
    python实现:
# -*- coding: utf-8 -*-
"""
拉格朗日插值代码
"""
import pandas as pd #导入数据分析库
from scipy.interpolate import lagrange #导入拉格朗日插值函数
inputfile = './missing_data.xls' #输入数据路径,需要使用Excel格式
outputfile = './missing_data_processed.xls'  #输出数据路径,需要使用Excel格式
#header表示数据中是否存在列名,如果在第0行就写0,并且开始读数据时跳过相应的行数,不存在可以写None
data = pd.read_excel(inputfile, header = None)
#自定义列向量插值函数
#s为列向量,n为被插值的位置,K为取前后的数据个数,默认为5
def ployinterp_column(s, n, k=5):
    y = s[list(range(n-k, n)) + list(range(n+1, n+1+k))] #取数,转换成列表
    y = y[y.notnull()] #剔除空值
    return lagrange(y.index, list(y))(n) #插值并返回插值结果,n是被插值的位置
 
#逐个元素判断是否需要插值
for i in data.columns:
    for j in range(len(data)):
        if (data[i].isnull())[j]: #如果为空即插值
            data[i][j] = ployinterp_column(data[i], j)
 
data.to_excel(outputfile, header = None, index = False) #输出结果
-  注意事项:
 -  稳定性不好 出现不稳定现象称为龙格现象,解决方法是分段低次数的插值多项式
  • 牛顿插值法
  • 分段插值
  • k-means
    • 通过K均值的聚类方法将所有样本进行聚类划分,然后再通过划分的种类的均值对各自类中的缺失值进行填补。归其本质还是通过找相似来填补缺失值。缺失值填补的准确性就要看聚类结果的好坏了,而聚类结果的可变性很大,通常与初始选择点有关,因此使用时要慎重。
    • knn填补空值
#用KNN填充空值
def knn_fill_nan(data,K):
    #计算每一行的空值,如果有空值,就进行填充;没有空值的行用于做训练数据
    data_row = data.isnull().sum(axis=1).reset_index()
    data_row.columns = ['raw_row','nan_count']
    #空值行(需要填充的行)
    data_row_nan = data_row[data_row.nan_count>0].raw_row.values
    
    #非空行,原始数据
    data_no_nan = data.drop(data_row_nan,axis=0)
    
    #空行,原始数据
    data_nan = data.loc[data_row_nan]
    
    for row in data_row_nan:
        data_row_need_fill = data_nan.loc[row]
        #找出空列,并用非空列做KNN
        data_col_index = data_row_need_fill.isnull().reset_index()
        data_col_index.columns = ['col','is_null']
        is_null_col = data_col_index[data_col_index.is_null == 1].col.values
        data_col_no_nan_index = data_col_index[data_col_index.is_null == 0].col.values
        #保存需要填充的行的非空列
        data_row_fill = data_row_need_fill[data_col_no_nan_index]
        
        #广播,矩阵-向量
        data_diff = data_no_nan[data_col_no_nan_index] - data_row_need_fill[data_col_no_nan_index]
        #求欧式距离
        data_diff = (data_diff ** 2).sum(axis=1)
        data_diff = data_diff.apply(lambda x:np.sqrt(x))
        data_diff = data_diff.reset_index()
        data_diff.columns = ['raw_row','diff_val']
        data_diff_sum = data_diff.sort_values(by='diff_val',ascending=True)
        data_diff_sum_sorted = data_diff_sum.reset_index()
        #取出k个距离最近的row
        top_k_diff_val = data_diff_sum_sorted.loc[0:K-1].raw_row.values
        #根据row和col值确定需要填充的数据的具体位置(可能是多个)
        #填充的数据为最近的K个值的平均值
        top_k_diff_val = data.loc[top_k_diff_val][is_null_col].sum(axis=0)/K
        #将计算出来的列添加至非空列
        data_row_fill = pd.concat([data_row_fill,pd.DataFrame(top_k_diff_val)]).T
        data_no_nan = data_no_nan.append(data_row_fill,ignore_index=True)
    print('填补完成')
    return data_no_nan

【2】拟合(适用于缺失值多)

  • 回归预测:缺失值是连续的,即定量的类型,才可以使用回归来预测。
  • 极大似然估计(Maximum likelyhood):在缺失类型为随机缺失的条件下,假设模型对于完整的样本是正确的,那么通过观测数据的边际分布可以对未知参数进行极大似然估计(Little and Rubin)。这种方法也被称为忽略缺失值的极大似然估计,对于极大似然的参数估计实际中常采用的计算方法是期望值最大化(Expectation Maximization,EM)。该方法比删除个案和单值插补更有吸引力,它一个重要前提:适用于大样本。有效样本的数量足够以保证ML估计值是渐近无偏的并服从正态分布。但是这种方法可能会陷入局部极值,收敛速度也不是很快,并且计算很复杂,且仅限于线性模型。
  • 多重插补(Mutiple imputation):多值插补的思想来源于贝叶斯估计,认为待插补的值是随机的,它的值来自于已观测到的值。具体实践上通常是估计出待插补的值,然后再加上不同的噪声,形成多组可选插补值。根据某种选择依据,选取最合适的插补值。  
    三步骤:
    为每个缺失值产生一套可能的插补值,这些值反映了无响应模型的不确定性;
    每个插补数据集合都用针对完整数据集的统计方法进行统计分析;
    对来自各个插补数据集的结果,根据评分函数进行选择,产生最终的插补值;

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

 -随机森林:将缺失值作为目标变量 
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

衍生

版权声明:本文为yijilei原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yijilei/article/details/102634937