手把手教你用pandas处理缺失值

大数据 数据分析
在进行数据分析和建模的过程中,大量的时间花在数据准备上:加载、清理、转换和重新排列。本文将讨论用于缺失值处理的工具。

[[381102]]

 pandas对象的所有描述性统计信息默认情况下是排除缺失值的。

pandas对象中表现缺失值的方式并不完美,但是它对大部分用户来说是有用的。对于数值型数据,pandas使用浮点值NaN(Not a Number来表示缺失值)。我们称NaN为容易检测到的标识值:

In :  

string_data = pd.Series(['aardvark', 'artichoke', np.nan, 'avocado']) 
  • 1.
string_data 
  • 1.

Out: 

0      aardvark  
1     artichoke  
2            NaN  
3       avocado  
dtype: object 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

In: 

string_data.isnull() 
  • 1.

Out: 

0     False  
1     False  
2      True  
3     False  
dtype: bool 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

在pandas中,我们采用了R语言中的编程惯例,将缺失值成为NA,意思是not available(不可用)。在统计学应用中,NA数据可以是不存在的数据或者是存在但不可观察的数据(例如在数据收集过程中出现了问题)。当清洗数据用于分析时,对缺失数据本身进行分析以确定数据收集问题或数据丢失导致的数据偏差通常很重要。

Python内建的None值在对象数组中也被当作NA处理:

In: 

string_data[0] = None 
  • 1.
string_data.isnull() 
  • 1.

Out: 

0      True  
1     False  
2      True  
3     False  
dtype: bool 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

pandas项目持续改善处理缺失值的内部细节,但是用户API函数,比如pandas. isnull,抽象掉了很多令人厌烦的细节。处理缺失值的相关函数列表如下:

  •  dropna:根据每个标签的值是否是缺失数据来筛选轴标签,并根据允许丢失的数据量来确定阈值
  •  fillna:用某些值填充缺失的数据或使用插值方法(如“ffill”或“bfill”)。
  •  isnull:返回表明哪些值是缺失值的布尔值
  •  notnull:isnull的反作用函数

01 过滤缺失值

有多种过滤缺失值的方法。虽然你可以使用pandas.isnull和布尔值索引手动地过滤缺失值,但dropna在过滤缺失值时是非常有用的。在Series上使用dropna,它会返回Series中所有的非空数据及其索引值:

In: 

from numpy import nan as NA  
  • 1.
data = pd.Series([1, NA, 3.5, NA, 7]) 
  • 1.
data.dropna() 
  • 1.

Out: 

0     1.0  
2     3.5  
4     7.0  
dtype: float64 
  • 1.
  • 2.
  • 3.
  • 4.

上面的例子与下面的代码是等价的:

In: 

data[data.notnull()] 
  • 1.

Out: 

0     1.0  
2     3.5  
4     7.0  
dtype: float64 
  • 1.
  • 2.
  • 3.
  • 4.

当处理DataFrame对象时,事情会稍微更复杂一点。你可能想要删除全部为NA或包含有NA的行或列。dropna默认情况下会删除包含缺失值的行:

In: 

data = pd.DataFrame([[1., 6.5, 3.], [1., NA, NA]  
                     [NA, NA, NA], [NA, 6.5, 3.]])  
  • 1.
  • 2.
cleaned = data.dropna()  
  • 1.
data 
  • 1.

Out: 

   0     1     2  
0  1.0  6.5  3.0  
1  1.0  NaN  NaN  
2  NaN  NaN  NaN  
3  NaN  6.5  3.0 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

In: 

cleaned 
  • 1.

Out: 

0     1     2  
 1.0  6.5  3.0 
  • 1.
  • 2.

传入how='all’时,将删除所有值均为NA的行:

In: 

data.dropna(how='all'
  • 1.

Out: 

     0    1    2  
0  1.0  6.5  3.0  
1  1.0  NaN  NaN  
3  NaN  6.5  3.0 
  • 1.
  • 2.
  • 3.
  • 4.

如果要用同样的方式去删除列,传入参数axis=1:

In: 

data[4] = NA  
  • 1.
data 
  • 1.

Out: 

     0    1    2   4  
0  1.0  6.5  3.0 NaN  
1  1.0  NaN  NaN NaN  
2  NaN  NaN  NaN NaN  
3  NaN  6.5  3.0 NaN 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

In: 

data.dropna(axis=1how='all'
  • 1.

Out: 

     0    1    2  
0  1.0  6.5  3.0  
1  1.0  NaN  NaN  
2  NaN  NaN  NaN  
3  NaN  6.5  3.0 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

过滤DataFrame的行的相关方法往往涉及时间序列数据。假设你只想保留包含一定数量的观察值的行。你可以用thresh参数来表示:

In: 

df = pd.DataFrame(np.random.randn(7, 3))  
  • 1.
df.iloc[:4, 1] = NA  
  • 1.
df.iloc[:2, 2] = NA  
  • 1.
df 
  • 1.

Out: 

          0         1         2  
0 -0.204708       NaN       NaN  
1 -0.555730       NaN       NaN  
2  0.092908       NaN  0.769023  
3  1.246435       NaN -1.296221  
4  0.274992  0.228913  1.352917  
5  0.886429 -2.001637 -0.371843  
6  1.669025 -0.438570 -0.539741 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

In: 

df.dropna() 
  • 1.

Out: 

         0         1         2  
4 0.274992  0.228913  1.352917  
5 0.886429 -2.001637 -0.371843  
6 1.669025 -0.438570 -0.539741 
  • 1.
  • 2.
  • 3.
  • 4.

In: 

df.dropna(thresh=2
  • 1.

Out: 

         0         1         2  
2 0.092908       NaN  0.769023  
3 1.246435       NaN -1.296221  
4 0.274992  0.228913  1.352917  
5 0.886429 -2.001637 -0.371843  
6 1.669025 -0.438570 -0.539741 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

02 补全缺失值

你有时可能需要以多种方式补全“漏洞”,而不是过滤缺失值(也可能丢弃其他数据)。

大多数情况下,主要使用fillna方法来补全缺失值。调用fillna时,可以使用一个常数来替代缺失值:

In: 

df.fillna(0) 
  • 1.

Out: 

          0         1         2  
0 -0.204708  0.000000  0.000000  
1 -0.555730  0.000000  0.000000  
2  0.092908  0.000000  0.769023  
3  1.246435  0.000000 -1.296221  
4  0.274992  0.228913  1.352917  
5  0.886429 -2.001637 -0.371843  
6  1.669025 -0.438570 -0.539741 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

在调用fillna时使用字典,你可以为不同列设定不同的填充值:

In: 

df.fillna({1: 0.5, 2: 0}) 
  • 1.

Out: 

         0         1         2  
0 -0.204708  0.500000  0.000000  
1 -0.555730  0.500000  0.000000  
2  0.092908  0.500000  0.769023  
3  1.246435  0.500000 -1.296221  
4  0.274992  0.228913  1.352917  
5  0.886429 -2.001637 -0.371843  
6  1.669025 -0.438570 -0.539741 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

fillna返回的是一个新的对象,但你也可以修改已经存在的对象:

In: 

_ = df.fillna(0, inplace=True
  • 1.
df 
  • 1.

Out: 

        0         1         2  
0 -0.204708  0.000000  0.000000  
1 -0.555730  0.000000  0.000000  
2  0.092908  0.000000  0.769023  
3  1.246435  0.000000 -1.296221  
4  0.274992  0.228913  1.352917  
5  0.886429 -2.001637 -0.371843  
6  1.669025 -0.438570 -0.539741 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

用于重建索引的相同的插值方法也可以用于fillna:

In: 

df = pd.DataFrame(np.random.randn(6, 3))  
  • 1.
df.iloc[2:, 1] = NA  
  • 1.
df.iloc[4:, 2] = NA  
  • 1.
df 
  • 1.

Out: 

         0         1         2  
0  0.476985  3.248944 -1.021228  
1 -0.577087  0.124121  0.302614  
2  0.523772       NaN  1.343810  
3 -0.713544       NaN -2.370232  
4 -1.860761       NaN       NaN  
5 -1.265934       NaN       NaN 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

In: 

df.fillna(method='ffill'
  • 1.

Out: 

          0         1         2  
0  0.476985  3.248944 -1.021228  
1 -0.577087  0.124121  0.302614  
2  0.523772  0.124121  1.343810  
3 -0.713544  0.124121 -2.370232  
4 -1.860761  0.124121 -2.370232  
5 -1.265934  0.124121 -2.370232 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

In: 

df.fillna(method='ffill'limit=2
  • 1.

Out: 

        0         1         2  
0  0.476985  3.248944 -1.021228  
1 -0.577087  0.124121  0.302614  
2  0.523772  0.124121  1.343810  
3 -0.713544  0.124121 -2.370232  
4 -1.860761       NaN -2.370232  
5 -1.265934       NaN -2.370232 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

使用fillna你可以完成很多带有一点创造性的工作。例如,你可以将Series的平均值或中位数用于填充缺失值:

In: 

data = pd.Series([1., NA, 3.5, NA, 7])  
  • 1.
data.fillna(data.mean()) 
  • 1.

Out: 

0     1.000000  
1     3.833333  
2     3.500000  
3     3.833333  
4     7.000000  
dtype: float64 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

以下是fillna的函数参数。

  •  value:标量值或字典型对象用于填充缺失值
  •  method:插值方法,如果没有其他参数,默认是'ffill'
  •  axis:需要填充的轴,默认axis=0
  •  inplace:修改被调用的对象,而不是生成一个备份
  •  limit:用于前向或后向填充时最大的填充范围

关于作者:韦斯·麦金尼(Wes McKinney)是流行的Python开源数据分析库pandas的创始人。他是一名活跃的演讲者,也是Python数据社区和Apache软件基金会的Python/C++开源开发者。目前他在纽约从事软件架构师工作。

本文摘编自《利用Python进行数据分析》(原书第2版),经出版方授权发布。 

 

责任编辑:庞桂玉 来源: 大数据DT
相关推荐

2021-08-02 23:15:20

Pandas数据采集

2022-04-01 20:29:26

Pandas数据存储

2021-08-09 13:31:25

PythonExcel代码

2022-10-19 14:30:59

2011-03-28 16:14:38

jQuery

2021-02-04 09:00:57

SQLDjango原生

2022-08-04 10:39:23

Jenkins集成CD

2021-09-02 08:56:48

JavaBMIHashSet

2021-02-10 09:34:40

Python文件的压缩PyCharm

2022-04-24 10:33:56

大数据数据分析

2009-04-22 09:17:19

LINQSQL基础

2021-05-09 22:41:43

Python数据统计

2021-05-10 06:48:11

Python腾讯招聘

2021-01-08 10:32:24

Charts折线图数据可视化

2021-01-21 09:10:29

ECharts柱状图大数据

2021-12-11 20:20:19

Python算法线性

2021-02-02 13:31:35

Pycharm系统技巧Python

2012-01-11 13:40:35

移动应用云服务

2020-03-08 22:06:16

Python数据IP

2017-10-27 10:29:35

人脸识别UbuntuPython
点赞
收藏

51CTO技术栈公众号