• 数据分析—NaN数据处理


    目的

      1.查找NaN值(定位到哪一列、在列的哪个索引位置)

      2.填充NaN值(向上填充、向下填充、线性填充等)

      3.过滤NaN值

    构建简单的Dataframe数据结构环境

    import pandas as pd
    import numpy as np
    
    #在df中nan和None都会被自动填充为NaN
    df=pd.DataFrame({'a':[np.nan,1,2,3],'b':[None,5,6,7],'c':[8,9,10,11]})
    print(df)
    
    '''结果 
         a    b   c
    0  NaN  NaN   8
    1  1.0  5.0   9
    2  2.0  6.0  10
    3  3.0  7.0  11
    
    '''

    注意点:

      1.None、nan在构建dataframe数据结构中都会被识别为NaN

      2.None与nan的类型是不一样的

    #nan是个特殊的float类型
    print(type(np.nan))  #<class 'float'>
    
    #None是NoneType
    print(type(None))   #<class 'NoneType'>

    #打印空值看输出结果
    print(df['a'][0])  #nan

    #作为字典的key时,会被认为是不同的key
    dic={None:1, NaN:2}
    print(dic) #{None: 1, nan: 2}

    目的1:查找NaN值

    原始数据:

    df=pd.DataFrame({'a':[0,1,np.nan,3,4],'b':[4,5,6,np.nan,8],'c':[9,10,np.nan,np.nan,13]})
    print(df)
    
    '''结果
         a    b     c
    0  0.0  4.0   9.0
    1  1.0  5.0  10.0
    2  NaN  6.0   NaN
    3  3.0  NaN   NaN
    4  4.0  8.0  13.0
    
    '''

    1.1 输出NaN值所在具体位置(调用math下面的isnan做判断)

    from math import isnan
    for i in df.columns:
        # print(df[i].values) 
        for k in range(len( df[i].values)):
            if isnan(df[i].values[k]):
                print('字段%s存在NaN值:' % i + '索引位置是:%s'%k)

    1.2 分别找到NaN值所在的列名、行名:np.isnan()

    import pandas as pd
    import numpy as np
    from math import isnan
    
    #在df中nan和None都会被自动填充为NaN
    df=pd.DataFrame({'a':[np.nan,1,2,3,4],'b':[4,5,6,np.nan,np.nan],'c':[9,10,np.nan,np.nan,np.nan]},index=['index_0','index_1','index_2','index_3','index_4'])
    print(df)
    '''原始数据
               a    b     c
    index_0  NaN  4.0   9.0
    index_1  1.0  5.0  10.0
    index_2  2.0  6.0   NaN
    index_3  3.0  NaN   NaN
    index_4  4.0  NaN   NaN
    '''
    #利用np.isnan(df),对整个df的NaN值做判断
    res=np.isnan(df)
    print(res)
    '''
                 a      b      c
    index_0   True  False  False
    index_1  False  False  False
    index_2  False  False   True
    index_3  False   True   True
    index_4  False   True   True
    
    '''
    
    nan_res=np.where(np.isnan(df))
    print(nan_res)  #(array([0, 2, 3, 3, 4, 4], dtype=int32), array([0, 2, 1, 2, 1, 2], dtype=int32))
    '''
    #得到一个元祖 
    (array([0, 2, 3, 3, 4, 4], dtype=int32), array([0, 2, 1, 2, 1, 2], dtype=int32))
    元祖第一个值:表示行索引(都是以数字表示)
    元祖第二个值:表示列索引(都是以数字表示)
    注意:看前后行、列索引列表的排序,发现是每一行的数据去逐一检索的
    '''
    
    #查看NaN值默认行号(数字)(有重复值时表示是这一行里有多个NaN值)
    print(nan_res[0]) #[0 2 3 3 4 4]
    print(nan_res[1]) #[0 2 1 2 1 2]
    
    #查看NaN值的行号名(即实际行号名字)
    nan_index_info=df.index[np.where(np.isnan(df))[0]]
    print(nan_index_info) #Index(['index_0', 'index_2', 'index_3', 'index_3', 'index_4', 'index_4'], dtype='object')
    
    #查看NaN值的列名
    nan_columns_info=df.columns[np.where(np.isnan(df))[1]]
    print(nan_columns_info) #Index(['a', 'c', 'b', 'c', 'b', 'c'], dtype='object')

    1.3 isnull、notnull

    isnull_res=df.isnull()
    print(isnull_res)
    '''
           a      b      c
    0  False  False  False
    1  False  False  False
    2   True  False   True
    3  False   True   True
    4  False  False  False
    
    '''

    1.4 isnull().values

    # 2.1 isnull().values
    isnull_res=df.isnull().values
    print(isnull_res)
    '''
    [[False False False]
     [False False False]
     [ True False  True]
     [False  True  True]
     [False False False]]
     
    '''

    1.5 isnull().sum() 统计显示

    #2.3 isnull().sum() 统计
    isnull_res=df.isnull().sum()
    print(isnull_res)
    '''
    a    1
    b    1
    c    2
    dtype: int64
    
    '''

     1.6 isnull().any() 布尔值,显示行里是不是有NaN值

    df=pd.DataFrame({'a':[0,1,np.nan,3,4],'b':[4,5,6,np.nan,8],'c':[9,10,np.nan,np.nan,13]})
    print(df)
    '''原始数据
         a    b     c
    0  0.0  4.0   9.0
    1  1.0  5.0  10.0
    2  NaN  6.0   NaN
    3  3.0  NaN   NaN
    4  4.0  8.0  13.0
    
    '''
    
    any_res=df.isnull().any()
    print(any_res)
    '''
    a    True
    b    True
    c    True
    dtype: bool
    
    '''

    目的2:填充NaN值

    原始数据样子:

    df=pd.DataFrame({'a':[0,1,np.nan,3,4],'b':[4,5,6,np.nan,8],'c':[9,10,np.nan,np.nan,13]})
    print(df)
    
    '''结果
         a    b     c
    0  0.0  4.0   9.0
    1  1.0  5.0  10.0
    2  NaN  6.0   NaN
    3  3.0  NaN   NaN
    4  4.0  8.0  13.0
    
    '''

    2.1 fillna直接填充

    #2.1.fillna直接填充
    df.fillna(0,inplace=True) #表示更新到源数据
    print(df)
    '''
         a    b     c
    0  0.0  4.0   9.0
    1  1.0  5.0  10.0
    2  0.0  6.0   0.0
    3  3.0  0.0   0.0
    4  4.0  8.0  13.0
    
    '''

    #另外一种方式
    res=df.where(df.notna(),100)

    fillna({字典})字典key:表示列索引  value:表示要填充的值

    df=pd.DataFrame({'a':[0,1,2,3,4],'b':[4,5,6,np.nan,8],'c':[9,10,np.nan,np.nan,13]})
    
    #意为将b列空值:填充为00 c列空值填充为:11
    df_new
    =df.fillna({'b':00,'c':11}) print(df_new) ''' a b c 0 0 4.0 9.0 1 1 5.0 10.0 2 2 6.0 11.0 3 3 0.0 11.0 4 4 8.0 13.0 '''

    2.2 向上填充(即取NaN后面一个数值作为填充):bfill

    fillna_res=df.fillna(method='bfill')
    print(fillna_res)
    '''
         a    b     c
    0  0.0  4.0   9.0
    1  1.0  5.0  10.0
    2  3.0  6.0  13.0
    3  3.0  8.0  13.0
    4  4.0  8.0  13.0
    
    '''

    2.3 向下填充(即取NaN前面一个数值作为填充):ffill

    fillna_res=df.fillna(method='ffill')
    print(fillna_res)
    '''
         a    b     c
    0  0.0  4.0   9.0
    1  1.0  5.0  10.0
    2  1.0  6.0  10.0
    3  3.0  6.0  10.0
    4  4.0  8.0  13.0
    
    '''

    2.4 用一个数据代替NaN:pad  (功能类似于向下填充ffill)

    fillna_res=df.fillna(method='pad')
    print(fillna_res)
    '''
         a    b     c
    0  0.0  4.0   9.0
    1  1.0  5.0  10.0
    2  1.0  6.0  10.0
    3  3.0  6.0  10.0
    4  4.0  8.0  13.0
    
    
    '''

    2.5 平均值替换:df.mean()

    #平均值替换:df.mean()
    fillna_res=df.fillna(df.mean())
    print(fillna_res)
    '''
         a     b          c
    0  0.0  4.00   9.000000
    1  1.0  5.00  10.000000
    2  2.0  6.00  10.666667
    3  3.0  5.75  10.666667
    4  4.0  8.00  13.000000
    
    '''

    2.6 指定替换具体列的NaN值

    #选择指定替换哪些列
    choose_fillna=df.fillna(df.mean()['a':'b'])
    print(choose_fillna)
    '''
         a     b     c
    0  0.0  4.00   9.0
    1  1.0  5.00  10.0
    2  2.0  6.00   NaN
    3  3.0  5.75   NaN
    4  4.0  8.00  13.0
    
    '''

    2.7 限制每列替换NaN的个数:limit=

    limit_res=df.fillna(df.mean(),limit=1)
    print(limit_res)
    '''
         a     b          c
    0  0.0  4.00   9.000000
    1  1.0  5.00  10.000000
    2  2.0  6.00  10.666667
    3  3.0  5.75        NaN
    4  4.0  8.00  13.000000
    
    '''

    2.8  线性插值 df.interpolate(),如果存在第一个值是NaN的情况,这个NaN值无法被替换,需要单独再判断

    df=pd.DataFrame({'a':[2,1,2,3,4],'b':[4,5,6,np.nan,2],'c':[9,10,np.nan,np.nan,4]},index=['index_0','index_1','index_2','index_3','index_4'])
    print(df)
    '''
             a    b     c
    index_0  2  4.0   9.0
    index_1  1  5.0  10.0
    index_2  2  6.0   NaN
    index_3  3  NaN   NaN
    index_4  4  2.0   4.0
    
    '''
    #实际上上前一个值和后一个值得平均数,因为interpolate()假设函数是直线形式
    print(df.interpolate())
    '''
             a    b     c
    index_0  2  4.0   9.0
    index_1  1  5.0  10.0
    index_2  2  6.0   8.0
    index_3  3  4.0   6.0
    index_4  4  2.0   4.0
    
    '''

    特殊情况的填充:

      重点:假设每一列数据的第一或最后为空(再用上面的普通方法就填充时就容易忽略掉1和最后的值)

    解决思路:

    #解决的一个问题是开头和结果都是NaN的情况
    1.判断如果开头是NaN取下面最近的数值填充
    2.如果结尾是NaN取上面最近的数值填充
    3.最后再对整体的中间NaN进行替换,就可以向上或向下取值了代码 

    初始数据结构:

    df=pd.DataFrame({'a':[np.nan,1,np.nan,3,4],'b':[None,5,np.nan,7,None],'c':[9,10,np.nan,12,13]})
    print(df)
    df=pd.DataFrame({'a':[np.nan,1,np.nan,3,4],'b':[None,5,np.nan,7,None],'c':[9,10,np.nan,12,13]})
    print(df)
    '''
         a    b     c
    0  NaN  NaN   9.0
    1  1.0  5.0  10.0
    2  NaN  NaN   NaN
    3  3.0  7.0  12.0
    4  4.0  NaN  13.0
    
    '''

    代码实现3个步骤:

    #循环没一个列的value值(判断)
    for i in df.columns:
        n=1
        for k in range(len(df[i].values)):
            #如果第一个值是NaN
            if isnan(df[i].values[0]):
                #找下面最近的不是NaN的值做填充
                if not isnan(df[i].values[k]):
                    df[i].values[0]=df[i].values[k]
    
                # print('说明第一个值是0,要替换成下面离他最近的一个数值')
    
            #如果最后一个值是NaN
            elif isnan(df[i].values[len(df[i].values)-1]):
                n+=1
                #再判断倒数第二个值看是否是NaN(依次往上找,找到不是NaN的值做替换)
                if not isnan(df[i].values[len(df[i].values)-n]):
                    df[i].values[len(df[i].values) - 1]=df[i].values[len(df[i].values)-n]
    
                # print('说明最后一个值是0,要替换成上面离他最近的一个数值')
                
        #最终对整体没一列中存在的NaN数据进行向前取值
        df=df.fillna(method='pad')
    
    print(df)

    目的3:过滤NaN值

     初始数据

    df=pd.DataFrame({'a':[0,1,2,3,4],'b':[4,5,6,np.nan,8],'c':[9,10,np.nan,np.nan,13]})
    print(df)
    '''
       a    b     c
    0  0  4.0   9.0
    1  1  5.0  10.0
    2  2  6.0   NaN
    3  3  NaN   NaN
    4  4  8.0  13.0
    
    '''

    3.1 删除存在NaN的行或列:dropna()

    #默认删除存在NaN的行:
    # res=df.dropna()
    # print(res)
    '''
       a    b     c
    0  0  4.0   9.0
    1  1  5.0  10.0
    4  4  8.0  13.0
    
    '''

    3.2 删除存在NaN的列:axis=1

    res=df.dropna(axis=1) #删除存在NaN的列
    print(res)
    '''
       a
    0  0
    1  1
    2  2
    3  3
    4  4
    
    '''

    3.3 删除全为NaN的how='all'

    #删除全为NaN的行
    all_res=df.dropna(how='all')
    print(all_res)

    3.4 删除全为NaN的列(axis=1,how='all')

    #删除全为NaN的列(axis=1,how='all')
    df=pd.DataFrame({'a':[0,1,2,np.nan,4],'b':[4,5,6,np.nan,8],'c':[np.nan,np.nan,np.nan,np.nan,np.nan]})
    print(df)
    '''
         a    b   c
    0  0.0  4.0 NaN
    1  1.0  5.0 NaN
    2  2.0  6.0 NaN
    3  NaN  NaN NaN
    4  4.0  8.0 NaN
    '''
    all_loc_res=df.dropna(axis=1,how='all')
    print(all_loc_res)
    '''
         a    b
    0  0.0  4.0
    1  1.0  5.0
    2  2.0  6.0
    3  NaN  NaN
    4  4.0  8.0
    
    '''

    3.5 dropna(thresh=2参数),过滤NaN时再做近一步的条件筛选

    #在df中nan和None都会被自动填充为NaN
    df=pd.DataFrame({'a':[np.nan,1,2,3,4],'b':[4,5,6,np.nan,np.nan],'c':[9,10,np.nan,np.nan,np.nan]},index=['index_0','index_1','index_2','index_3','index_4'])
    print(df)
    '''原始数据
               a    b     c
    index_0  NaN  4.0   9.0
    index_1  1.0  5.0  10.0
    index_2  2.0  6.0   NaN
    index_3  3.0  NaN   NaN
    index_4  4.0  NaN   NaN
    
    '''
    
    #过滤取值,保留在行方向上至少有3个非空的项:dropna(thresh=2)
    res=df.dropna(thresh=2)
    print(res)
    '''
               a    b     c
    index_0  NaN  4.0   9.0
    index_1  1.0  5.0  10.0
    index_2  2.0  6.0   NaN
    
    '''
    
    #过滤取值,保留在列方向上至少有3个非空的项
    res=df.dropna(thresh=3,axis=1)
    print(res)
    '''
               a    b
    index_0  NaN  4.0
    index_1  1.0  5.0
    index_2  2.0  6.0
    index_3  3.0  NaN
    index_4  4.0  NaN
    
    '''
  • 相关阅读:
    matlab矩阵和矩阵操作基础
    [ZZ] MathType转化为LaTeX公式语言
    [综] 粒子滤波
    [综] Endnote怎么下载杂志格式?
    英语句子的连接方式
    [zz] postscript打印机以及ps文件转eps文件
    [zz]SCI投稿经验
    all, whole, entire, total, complete
    [转] 动态规划 最短路径
    [zz] Dynamic Time Warping 动态时间规整(弯折)
  • 原文地址:https://www.cnblogs.com/yangzhizong/p/10271179.html
Copyright © 2020-2023  润新知