当前位置:   article > 正文

pandas 缺失数据处理大全

pandas处理缺失值

daf21158605bebd718c8c4f72b099cdf.gif

作者 | 东哥起飞

来源 | 东哥起飞

利用闲暇之余将有关数据清洗、数据分析的一些技能再次进行分类,里面也包含了我平时用到的一些小技巧,此次就从数据清洗缺失值处理走起~

所有数据和代码可在我的GitHub获取:

https://github.com/xiaoyusmd/PythonDataScience

一、缺失值类型

pandas中,缺失数据显示为NaN。缺失值有3种表示方法,np.nannonepd.NA

1、np.nan

缺失值有个特点(坑),它不等于任何值,连自己都不相等。如果用nan和任何其它值比较都会返回nan

  1. np.nan == np.nan
  2. >> False

也正由于这个特点,在数据集读入以后,不论列是什么类型的数据,默认的缺失值全为np.nan

因为nanNumpy中的类型是浮点,因此整型列会转为浮点;而字符型由于无法转化为浮点型,只能归并为object类型('O'),原来是浮点型的则类型不变。

  1. type(np.nan)
  2. >> float
  1. pd.Series([1,2,3]).dtype
  2. >> dtype('int64')
  3. pd.Series([1,np.nan,3]).dtype
  4. >> dtype('float64')

初学者做数据处理遇见object类型会发懵,不知道这是个啥,明明是字符型,导入后就变了,其实是因为缺失值导致的。

除此之外,还要介绍一种针对时间序列的缺失值,它是单独存在的,用NaT表示,是pandas的内置类型,可以视为时间序列版的np.nan,也是与自己不相等。

  1. s_time = pd.Series([pd.Timestamp('20220101')]*3)
  2. s_time
  3. >> 0 2022-01-01
  4.    1 2022-01-01
  5.    2 2022-01-01
  6.    dtype:datetime64[ns]
  7. -----------------
  8. s_time[2] = pd.NaT
  9. s_time
  10. >> 0 2022-01-01
  11.    1 2022-01-01
  12.    2 NaT
  13.    dtype:datetime64[ns]

2、None

还有一种就是None,它要比nan好那么一点,因为它至少自己与自己相等。

  1. None == None
  2. >> True

在传入数值类型后,会自动变为np.nan

  1. type(pd.Series([1,None])[1])
  2. >> numpy.float64

只有当传入object类型时是不变的,因此可以认为如果不是人工命名为None的话,它基本不会自动出现在pandas中,所以None大家基本也看不到。

  1. type(pd.Series([1,None],dtype='O')[1])
  2. >> NoneType

3、NA标量

pandas1.0以后的版本中引入了一个专门表示缺失值的标量pd.NA,它代表空整数、空布尔值、空字符,这个功能目前处于实验阶段。

开发者也注意到了这点,对于不同数据类型采取不同的缺失值表示会很乱。pd.NA就是为了统一而存在的。pd.NA的目标是提供一个缺失值指示器,可以在各种数据类型中一致使用(而不是np.nan、None或者NaT分情况使用)。

  1. s_new = pd.Series([12], dtype="Int64")
  2. s_new
  3. >> 0   1
  4.    1   2
  5.    dtype: Int64
  6. -----------------
  7. s_new[1] = pd.NaT
  8. s_new
  9. >> 0    1
  10.    1  <NA>
  11.    dtype: Int64

同理,对于布尔型、字符型一样不会改变原有数据类型,这样就解决了原来动不动就变成object类型的麻烦了。

下面是pd.NA的一些常用算术运算和比较运算的示例:

  1. ##### 算术运算
  2. # 加法
  3. pd.NA + 1
  4. >> <NA>
  5. -----------
  6. # 乘法
  7. "a" * pd.NA
  8. >> <NA>
  9. -----------
  10. # 以下两种其中结果为1
  11. pd.NA ** 0
  12. >> 1
  13. -----------
  14. 1 ** pd.NA
  15. >> 1
  16. ##### 比较运算
  17. pd.NA == pd.NA
  18. >> <NA>
  19. -----------
  20. pd.NA < 2.5
  21. >> <NA>
  22. -----------
  23. np.log(pd.NA)
  24. >> <NA>
  25. -----------
  26. np.add(pd.NA, 1)
  27. >> <NA>

二、缺失值判断

了解了缺失值的几种形式后,我们要知道如何判断缺失值。对于一个dataframe而言,判断缺失的主要方法就是isnull()或者isna(),这两个方法会直接返回TrueFalse的布尔值。可以是对整个dataframe或者某个列。

  1. df = pd.DataFrame({
  2.       'A':['a1','a1','a2','a3'],
  3.       'B':['b1',None,'b2','b3'],
  4.       'C':[1,2,3,4],
  5.       'D':[5,None,9,10]})
  6. # 将无穷设置为缺失值      
  7. pd.options.mode.use_inf_as_na = True

1、对整个dataframe判断缺失

  1. df.isnull()
  2. >> A B C D
  3. 0 False False False False
  4. 1 False True False True
  5. 2 False False False False
  6. 3 False False False False

2、对某个列判断缺失

  1. df['C'].isnull()
  2. >> 0    False
  3.    1    False
  4.    2    False
  5.    3    False
  6. Name: C, dtype: bool

如果想取非缺失可以用notna(),使用方法是一样的,结果相反。

三、缺失值统计

1、列缺失

一般我们会对一个dataframe进行缺失统计,查看每个列有多少缺失,如果缺失率过高再进行删除或者插值等操作。那么直接在上面的isnull()返回的结果上直接应用.sum()即可,axis默认等于0,0是列,1是行。

  1. ## 列缺失统计
  2. isnull().sum(axis=0)

2、行缺失

但是很多情况下,我们也需要对进行缺失值判断。比如一行数据可能一个值都没有,如果这个样本进入模型,会造成很大的干扰。因此,行列两个缺失率通常都要查看并统计。

操作很简单,只需要在sum()中设置axis=1即可。

  1. ## 行缺失统计
  2. isnull().sum(axis=1)

3、缺失率

有时我不仅想要知道缺失的数量,我更想知道缺失的比例,即缺失率。正常可能会想到用上面求得数值再比上总行数。但其实这里有个小技巧可以一步就实现。

  1. ## 缺失率
  2. df.isnull().sum(axis=0)/df.shape[0]
  3. ## 缺失率(一步到位)
  4. isnull().mean()

四、缺失值筛选

筛选需要loc配合完成,对于行和列的缺失筛选如下:

  1. # 筛选有缺失值的行
  2. df.loc[df.isnull().any(1)]
  3. >> A B C D
  4. 1 a1 None 2 NaN
  5. -----------------
  6. # 筛选有缺失值的列
  7. df.loc[:,df.isnull().any()]
  8. >> B D
  9. 0 b1 5.0
  10. 1 None NaN
  11. 2 b2 9.0
  12. 3 b3 10.0

如果要查询没有缺失值的行和列,可以对表达式用取反~操作:

  1. df.loc[~(df.isnull().any(1))]
  2. >> A B C D
  3. 0 a1 b1 1 5.0
  4. 2 a2 b2 3 9.0
  5. 3 a3 b3 4 10.0

上面使用了any判断只要有缺失就进行筛选,也可以用all判断是否全部缺失,同样可以对行里进行判断,如果整列或者整行都是缺失值,那么这个变量或者样本就失去了分析的意义,可以考虑删除。

五、缺失值填充

一般我们对缺失值有两种处理方法,一种是直接删除,另外一种是保留并填充。下面先介绍填充的方法fillna

  1. # 将dataframe所有缺失值填充为0
  2. df.fillna(0)
  3. >> A B C D
  4. 0 a1 b1 1 5.0
  5. 1 a1 0 2 0.0
  6. 2 a2 b2 3 9.0
  7. 3 a3 b3 4 10.0
  8. --------------
  9. # 将D列缺失值填充为-999
  10. df.D.fillna('-999')
  11. >> 0       5
  12.    1    -999
  13.    2       9
  14.    3      10
  15. Name: D, dtype: object

方法很简单,但使用时需要注意一些参数。

  • inplace:可以设置fillna(0, inplace=True)来让填充生效,原dataFrame被填充。

  • methond:可以设置methond方法来实现向前或者向后填充,pad/ffill为向前填充,bfill/backfill为向后填充,比如df.fillna(methond='ffill'),也可以简写为df.ffill()

  1. df.ffill()
  2. >> A B C D
  3. 0 a1 b1 1 5.0
  4. 1 a1 b1 2 5.0
  5. 2 a2 b2 3 9.0
  6. 3 a3 b3 4 10.0

原缺失值都会按照前一个值来填充(B列1行,D列1行)。

除了用前后值来填充,也可以用整个列的均值来填充,比如对D列的其它非缺失值的平均值8来填充缺失值。

  1. df.D.fillna(df.D.mean())
  2. >> 0     5.0
  3.    1     8.0
  4.    2     9.0
  5.    3    10.0
  6. Name: D, dtype: float64

六、缺失值删除

删除缺失值也非情况,比如是全删除还是删除比较高缺失率,这个要看自己的容忍程度,真实的数据必然会存在缺失的,这个无法避免。而且缺失在某些情况下也代表了一定的含义,要视情况而定。

1、全部直接删除

  1. # 全部直接删除
  2. df.dropna()
  3. >> A B C D
  4. 0 a1 b1 1 5.0
  5. 2 a2 b2 3 9.0
  6. 3 a3 b3 4 10.0

2、行缺失删除

  1. # 行缺失删除
  2. df.dropna(axis=0)
  3. >> A B C D
  4. 0 a1 b1 1 5.0
  5. 2 a2 b2 3 9.0
  6. 3 a3 b3 4 10.0

3、列缺失删除

  1. # 列缺失删除
  2. df.dropna(axis=1)
  3. >> A C
  4. 0 a1 1
  5. 1 a1 2
  6. 2 a2 3
  7. 3 a3 4
  8. -------------
  9. # 删除指定列范围内的缺失,因为C列无缺失,所以最后没有变化
  10. df.dropna(subset=['C'])
  11. >> A B C D
  12. 0 a1 b1 1 5.0
  13. 1 a1 None 2 NaN
  14. 2 a2 b2 3 9.0
  15. 3 a3 b3 4 10.0

4、按缺失率删除

这个可以考虑用筛选的方法来实现,比如要删除列缺失大于0.1的(即筛选小于0.1的)。

  1. df.loc[:,df.isnull().mean(axis=0) < 0.1]
  2. >> A C
  3. 0 a1 1
  4. 1 a1 2
  5. 2 a2 3
  6. 3 a3 4
  7. -------------
  8. # 删除行缺失大于0.1
  9. df.loc[df.isnull().mean(axis=1) < 0.1]
  10. >> A B C D
  11. 0 a1 b1 1 5.0
  12. 2 a2 b2 3 9.0
  13. 3 a3 b3 4 10.0

七、缺失值参与计算

如果不对缺失值处理,那么缺失值会按照什么逻辑进行计算呢?

下面我们一起看一下各种运算下缺失值的参与逻辑。

1、加法

  1. df
  2. >>A B C D
  3. 0 a1 b1 1 5.0
  4. 1 a1 None 2 NaN
  5. 2 a2 b2 3 9.0
  6. 3 a3 b3 4 10.0
  7. ---------------
  8. # 对所有列求和
  9. df.sum()
  10. >> A    a1a1a2a3
  11.    C          10
  12.    D          24

可以看到,加法是会忽略缺失值的。

2、累加

  1. # 对D列进行累加
  2. df.D.cumsum()
  3. >> 0     5.0
  4.    1     NaN
  5.    2    14.0
  6.    3    24.0
  7. Name: D, dtype: float64
  8. ---------------
  9. df.D.cumsum(skipna=False)
  10. >> 0    5.0
  11.    1    NaN
  12.    2    NaN
  13.    3    NaN
  14. Name: D, dtype: float64

cumsum累加会忽略NA,但值会保留在列中,可以使用skipna=False跳过有缺失值的计算并返回缺失值。

3、计数

  1. # 对列计数
  2. df.count()
  3. >> A    4
  4.    B    3
  5.    C    4
  6.    D    3
  7. dtype: int64

缺失值不进入计数范围里。

4、聚合分组

  1. df.groupby('B').sum()
  2. >> C D
  3. B  
  4. b1 1 5.0
  5. b2 3 9.0
  6. b3 4 10.0
  7. ---------------
  8. df.groupby('B',dropna=False).sum()
  9. >> C D
  10. B  
  11. b1 1 5.0
  12. b2 3 9.0
  13. b3 4 10.0
  14. NaN 2 0.0

聚合时会默认忽略缺失值,如果要缺失值计入到分组里,可以设置dropna=False。这个用法和其它比如value_counts是一样的,有的时候需要看缺失值的数量。

以上就是所有关于缺失值的常用操作了,从理解缺失值的3种表现形式开始,到缺失值判断、统计、处理、计算等。

4eddbe9581a064231b3af8bedac7ba71.gif

往期回顾

NLP 类问题建模方案探索实践

Python 爬虫中的常见加密算法!

2D变身3D,来看英伟达的AI“新”魔法!

搞定Python几个常用的数据结构!

  1. 分享
  2. 点收藏
  3. 点点赞
  4. 点在看
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/秋刀鱼在做梦/article/detail/931811
推荐阅读
相关标签
  

闽ICP备14008679号