• Task07|缺失数据|DataWhale组队学习


    第七章 缺失数据

    ```python import numpy as np import pandas as pd ```

    一、缺失值的统计和删除

    1. 缺失信息的统计

    缺失数据可以使用isnaisnull(两个函数没有区别)来查看每个单元格是否缺失,结合mean可以计算出每列缺失值的比例:

    df = pd.read_csv('../data/learn_pandas.csv', usecols = ['Grade', 'Name', 'Gender', 'Height', 'Weight', 'Transfer'])
    df.isna().head()
    df.isna().mean() # 查看缺失的比例
    df[df.Height.isna()].head()
    df[df.Height.notna()].head()
    sub_set=df[['Height','Weight','Transfer']]
    df[sub_set.isna().all(1)]#全部缺失
    df[sub_set.isna().any(1)].head() # 至少有一个缺失
    df[sub_set.notna().all(1)].head()
    #没有缺失
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2. 缺失信息的删除

    dropna的主要参数为轴方向axis(默认为0,即删除行)、删除方式how、删除的非缺失值个数阈值thresh 非缺失值 \color{red}{非缺失值} 非缺失值没有达到这个数量的相应维度会被删除)、备选的删除子集subset,其中how主要有anyall两种参数可以选择。

    res=df.dropna(how='any',subset=['Height','Weight'])
    res.shape
    
    #使用布尔索引
    res=df.loc[df[['Height','Weight']].notna().all(1)]
    res.shape
    
    #删除超过15个缺失值的列:
    res=df.dropna(1,thresh=df.shape[0]-15)
    # 身高被删除 thresh阈值
    res.head()
    
    res=df.loc[:,~(df.isna().sum()>15)]
    res.head()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    二、缺失值的填充和插值

    1. 利用fillna进行填充

    在fillna有三个参数是经常使用的
    value,method,limit

    value为填充值,可以是标量,也可以是索引到元素的字典映射
    method为填充方法,有用前面的元素填充ffill和用后面的元素填充bfill两种类型
    limit参数表示连续缺失值的最大填充次数。

    
    s=pd.Series([np.na])
    
    #缺失值的填充和插值
    s=pd.Series([np.nan,1,np.nan,np.nan,2,np.nan],list('aabcdf'))
    s
    s.fillna(method='ffill')
    s.fillna(method='bfill')
    
    s.fillna(s.mean())
    s.fillna({'a':100,'d':200,'f':300})
    #通过索引映射填充的值
    
    #通过分组,根据年级进行身高的均值填充
    df.groupby('Grade')['Height'].transform(lambda x:x.fillna(x.mean())).head()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    【练一练】

    对一个序列以如下规则填充缺失值:如果单独出现的缺失值,就用前后均值填充,如果连续出现的缺失值就不填充,即序列[1, NaN, 3, NaN, NaN]填充后为[1, 2, 3, NaN, NaN],请利用fillna函数实现。(提示:利用limit参数)

    temps=pd.Series([1,np.nan,3,np.nan,np.nan,np.nan])
    
    s1=temps.fillna(method='ffill',limit=1)
    s2=temps.fillna(method='bfill',limit=1)
    print(s2)
    print(s1)
    s_new=(s1+s2)/2
    print(s_new)
    
    #总结一个函数
    def convert_series(s):
        s1=s.fillna(method='ffill',limit=1)
        s2=s.fillna(method='bfill',limit=1)
        s_new=(s1+s2)/2
        return s_new
    s_new2=convert_series(pd.Series([1,np.nan,3,np.nan,np.nan]))
    print(s_new2)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2. 插值函数

    插值函数文档,interpolate 文档

    列举了许多插值方法,引用了大量Scipy中的方法

    线性插值,最近邻插值,索引插值

    对于interpolate而言,除了插值方法(默认为linear线性插值)之外
    有与fillna类似的两个常用参数

    • 一个是控制方向的limit_direction
    • 是控制最大连续缺失值插值个数的limit

    限制插值的方向默认为forward,与method中的ffill
    backword对应与bfill
    双向限制插值both

    s=pd.Series([np.nan,np.nan,1,np.nan,np.nan,np.nan,2,np.nan,np.nan])
    s.values
    res=s.interpolate(limit_direction='backward',limit=1)
    res.values
    #array([ nan, 1.  , 1.  ,  nan,  nan, 1.75, 2.  ,  nan,  nan])
    #后向限制插值
    # res=s.interpolate(li)
    
    #双向限制插值
    res=s.interpolate(limit_direction='both',limit=1)
    res
    #array([ nan, 1.  , 1.  , 1.25,  nan, 1.75, 2.  , 2.  ,  nan])
    
    #邻近插值
    res=s.interpolate('nearest').values
    res
    #array([nan, nan,  1.,  1.,  1.,  2.,  2., nan, nan])
    
    #索引插值
    s=pd.Series([0,np.nan,10],index=[0,1,10])
    res=s.interpolate()
    print(res.values)
    #[ 0.  5. 10.]
    #默认的线性插值等于计算中点的值
    
    s.interpolate(method='index')
    #和索引有关的线性插值,计算相应索引大小对应的值
    #array([ 0.,  1., 10.])
    
    #对于时间戳索引有关的值
    s=pd.Series([0,np.nan,10,np.nan],index=pd.to_datetime(['20200101','20200102','20200111','20200222']))
    s
    # 2020-01-01     0.0
    # 2020-01-02     NaN
    # 2020-01-11    10.0
    
    s.interpolate()
    # 2020-01-01     0.0
    # 2020-01-02     5.0
    # 2020-01-11    10.0
    
    s.interpolate(method='index')
    # 2020-01-01     0.0
    # 2020-01-02     1.0
    # 2020-01-11    10.0
    # 2020-02-22    10.0
    # dtype: float64
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    【NOTE】关于polynomial和spline插值的注意事项

    interpolate polynomial 是样条插值
    interpolate spine Univariate Spline 不是普通的样条插值

    interpolate中如果选用polynomial的插值方法,它内部调用的是scipy.interpolate.interp1d(*,*,kind=order),这个函数内部调用的是make_interp_spline方法,因此其实是样条插值而不是类似于numpy中的polyfit多项式拟合插值;而当选用spline方法时,pandas调用的是scipy.interpolate.UnivariateSpline而不是普通的样条插值。这一部分的文档描述比较混乱,而且这种参数的设计也是不合理的,当使用这两类插值方法时,用户一定要小心谨慎地根据自己的实际需求选取恰当的插值方法。

    三、Nullable类型

    1. 缺失记号及其缺陷

    python中的缺失值使用None表示

    
    #1. python中缺失值用None表示,与其他元素不相等
    None == None
    #True
    None==False
    #False
    None==[]
    #False
    None==''
    #False
    
    #2。 numpy 中利用np.nan表示缺失值,自己也不等 
    np.nan=np.nan
    #False
    np.nan==None
    #False
    np.nan==False
    #False
    
    s1=pd.Series([1,np.nan])
    s2=pd.Series([1,np.nan,np.nan])
    s3=pd.Series([1,np.nan])
    s4=pd.Series([1,2])
    s1==1
    #会进行广播然后比较
    # 0     True
    # 1    False
    s1.equals(s2)
    #False
    s1.equals(s3)
    #True
    s1.equals(s4)
    #False
    
    
    #3. 在时间序列对象中,pandas使用pd.NaT指代缺失值(作用与np.nan一致)
    pd.to_timedelta(['30s',np.nan])
    #Timedelta中的naT
    #TimedeltaIndex(['0 days 00:00:30', NaT], dtype='timedelta64[ns]', freq=None)
    pd.to_datetime(['20200101',np.nan])
    #Datetime中的naT
    #DatetimeIndex(['2020-01-01', 'NaT'], dtype='datetime64[ns]', freq=None)
    
    #为什么引入pd.NaT 表示时间对象中的缺失值
    #np.nan有什么问题
    #出现多个类型元素同时存储在Series的时候类型就会变为object#object是一种混杂对象类型
    pd.Series([1,'two'])
    # 0      1
    # 1    two
    # dtype: object
    type(np.nan)
    #float
    #NaT问题的根源来自于np.nan本身是一种浮点类型
    #如果浮点类型和时间类型混合存储,不涉及新的内置缺失类型来处理,就会变成含糊不清的object类型
    #由于np.nan浮点类型,如果在一个整数的Series出现缺失,类型会转变为float64
    #如果在一个布尔类型的序列出现缺失类型会转变为object而不是bool
    pd.Series([1,np.nan]).dtype
    #dtype('float')
    pd.Series([True,False,np.nan]).dtype
    #dtype('O')
    
    
    #1.0.0后pandas引入缺失类型pd.NA,以及三种Nullable序列类型来对这些缺陷
    #Int,boolean和string
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    2. Nullable类型的性质

    Nullable是可空的,序列不受缺失值的影响
    在上述Nullable类型中存储缺失值会转为pandas 内置的pd.NA

    s=pd.Series([np.nan,1],dtype='Int64')
    print(s)
    # 0    
    # 1       1
    # dtype: Int64
    pd.Series([np.nan,True],dtype='boolean')
    # 0    
    # 1    True
    # dtype: boolean
    pd.Series([np.nan,'my_str'],dtype='string')
    # 0      
    # 1    my_str
    # dtype: string
    
    pd.Series([np.nan, 0], dtype = 'Int64') + 1
    # 0    
    # 1       1
    # dtype: Int64
    
    pd.Series([np.nan, 0], dtype = 'Int64') == 0
    # 0    
    # 1    True
    # dtype: boolean
    
    pd.Series([np.nan, 0], dtype = 'Int64') * 0.5 # 只能是浮点
    # 0    NaN
    # 1    0.0
    # dtype: float64
    
    #对于boolean序列,与bool序列的行为是
    #1. `boolean`会把缺失值看作`False
    #带有缺失的布尔列表无法进行索引器中的选择
    
    s=pd.Series(['a','b'])
    s_bool=pd.Series([True,np.nan])
    s_boolean=pd.Series([True,np.nan]).astype('boolean')
    s[s_boolean]
    # s[s_bool]# 报错
    
    #2. 进行逻辑运算的时候bool类型在缺失值出永远返回False
    # boolean根据逻辑运算是否能够确定唯一结果来返回相应的值
    #True|pd.NA返回True,False|pd.NA 返回pd.NA
    #False&pd.NA返回False,pd.NA&True返回pd.NA
    #~pd.NA返回pd.NA
    ~s_boolean
    s_boolean&True
    s_boolean|True
    
    
    #关于string在文本数据讨论
    #实际数据处理时,可以在数据集读入之后,先通过convert_dtypes转为Nullable类型
    df=pd.read_csv('../data/learn_pandas.csv')
    df=df.convert_dtypes()#将数据类型转换为Nullable类型
    df.dtypes
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    3. 缺失数据的计算和分组

    当调用函数sum,prod使用加法和乘法的时候,缺失数据等价于被视作0和1,不改变原来的计算结果

    s=pd.Series([2,3,np.nan,4,5])
    s.sum()
    #14
    s.prod()
    #120
    
    #使用累计函数的时候,自动跳过缺失值所在的位置
    s.cumsum()
    #0     2.0
    # 1     5.0
    # 2     NaN
    # 3     9.0
    # 4    14.0
    
    #进行单个标量计算的时候,除了np.nan **0 和1**np.nan
    #所有运算结果全为缺失
    np.nan**0#1.0
    1**np.nan#1.0
    #np.nan比较操作的时候一定返回False, pd.NA返回pd.NA
    np.nan==0
    #False
    pd.NA==0
    #
    np.nan>0
    #False
    pd.NA>0
    #
    
    np.nan+1
    #nan
    np.log(np.nan)
    #nan
    np.add(np.nan,1)
    #nan
    np.nan**0
    #1.0
    1**np.nan
    #1.0
    pd.NA**0
    #1
    1**pd.NA
    #1
    
    #diff参与缺失值计算的部分全部设置为缺失值
    #pct_change缺失值位置会被设置为0%的变化率
    s.diff()
    # 0    NaN
    # 1    1.0
    # 2    NaN
    # 3    NaN
    # 4    1.0
    # dtype: float64
    s.pct_change()
    # 0         NaN
    # 1    0.500000
    # 2    0.000000
    # 3    0.333333
    # 4    0.250000
    # dtype: float64
    
    #对于一些函数而言,缺失可以作为一个类别处理,
    #在groupby,get_dummies中可以设置相应的参数来进行增加确实类别
    df_nan=pd.DataFrame({'category':['a','a','b',np.nan,np.nan],
                         'value':[1,3,5,7,9]})
    df_nan
    # 	category	value
    # 0	a	1
    # 1	a	3
    # 2	b	5
    # 3	NaN	7
    # 4	NaN	9
    df_nan.groupby('category',dropna=False)['value'].mean()
    #pandas版本大于1.1.0
    # category
    # a      2
    # b      5
    # NaN    8
    
    pd.get_dummies(df_nan.category,dummy_na=True)
    # 在`groupby, get_dummies`中可以设置相应的参数来进行增加缺失类别
    # 	a	b	NaN
    # 0	1	0	0
    # 1	1	0	0
    # 2	0	1	0
    # 3	0	0	1
    # 4	0	0	1
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88

    四、练习

    Ex1:缺失值与类别的相关性检验

    在数据处理中,含有过多缺失值的列往往会被删除,除非缺失情况与标签强相关。下面有一份关于二分类问题的数据集,其中X_1, X_2为特征变量,y为二分类标签。

    df = pd.read_csv('../data/missing_chi.csv')
    df.head()
    # 	X_1	X_2	y
    # 0	NaN	NaN	0
    # 1	NaN	NaN	0
    # 2	NaN	NaN	0
    # 3	43.0NaN	0
    # 4	NaN	NaN	0
    df.isna().mean()
    # X_1    0.855
    # X_2    0.894
    # y      0.000
    # dtype: float64
    df.y.value_counts(normalize=True)
    # 0    0.918
    # 1    0.082
    # Name: y, dtype: float64
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这里是引用

  • 相关阅读:
    Spring cloud负载均衡@LoadBalanced & LoadBalancerClient
    LabVIEW合并VI
    MySQL锁的类型及加锁范围
    C#重写方法和隐藏方法
    数据分享|R语言生态学种群空间点格局分析:聚类泊松点过程对植物、蚂蚁巢穴分布数据可视化...
    组合控件——底部标签栏——利用BottomNavigationView实现底部标签栏
    MySQL十秒插入百万条数据
    2023.11.16使用原生js和canvas实现图片矩形框标注功能
    SSM+基于web的《计算机基础》自学系统的设计与开发 毕业设计-附源码221509
    第三章 常用布局
  • 原文地址:https://blog.csdn.net/m0_52024881/article/details/126685934