pandas中的缺失数据表示
缺失数据在pandas中呈现的方式有些不完美,但对于大多数用户可以保证功能正常。对于数值数据,pandas使用浮点值NaN(Not a Number)表示缺失数据。我们称其为哨兵值,可以方便的检测出来
In [3]: string_data = pd.Series(['aardvark', 'artichoke', np.nan, 'avocado'])
In [4]: string_data
Out[4]:
0 aardvark
1 artichoke
2 NaN
3 avocado
dtype: object
In [5]: string_data.isnull()
Out[5]:
0 False
1 False
2 True
3 False
dtype: bool
在pandas中,我们采用了R语言中的惯用法,即将缺失值表示为NA,它表示不可用not available。在统计应用中,NA数据可能是不存在的数据或者虽然存在,但是没有观察到(例如,数据采集中发生了问题)。当进行数据清洗以进行分析时,最好直接对缺失数据进行分析,以判断数据采集的问题或缺失数据可能导致的偏差
Python内置的 None
值在对象数组中也可以作为NA:
In [6]: string_data[0] = None
In [7]: string_data.isnull()
Out[7]:
0 True
1 False
2 True
3 False
dtype: bool
pandas项目中还在不断优化内部细节以更好处理缺失数据,像用户API功能,例如pandas.isnull()
,去除了许多恼人的细节。下表列出了一些关于缺失数据处理的函数
滤除缺失数据
过滤掉缺失数据的办法有很多种。你可以通过pandas.isnull()
或布尔索引的手工方法,但dropna()
可能会更实用一些。对于一个Series,dropna
返回一个仅含非空数据和索引值的Series
In [10]: from numpy import nan as NA
In [11]: data = pd.Series([1, NA, 3.5, NA, 7])
In [12]: data.dropna()
Out[12]:
0 1.0
2 3.5
4 7.0
dtype: float64
这等价于
In [13]: data[data.notnull()]
Out[13]:
0 1.0
2 3.5
4 7.0
dtype: float64
而对于DataFrame对象,事情就有点复杂了。你可能希望丢弃全NA或含有NA的行或列。dropna()
默认丢弃任何含有缺失值的行
In [15]: data = pd.DataFrame([[1., 6.5, 3.], [1., NA, NA],
...: [NA, NA, NA], [NA, 6.5, 3.]])
In [16]: data
Out[16]:
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
In [17]: cleaned = data.dropna()
In [18]: data
Out[18]:
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
In [19]: cleaned
Out[19]:
0 1 2
0 1.0 6.5 3.0
传入 how='all'
将只丢弃全为NA的那些行
In [20]: data.dropna(how='all')
Out[20]:
0 1 2
0 1.0 6.5 3.0
1 1.0 NaN NaN
3 NaN 6.5 3.0
用这种方式丢弃列,只需传入axis=1
即可
In [21]: data[4] = NA
In [22]: data
Out[22]:
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
In [24]: data.dropna(axis=1, how='all')
Out[24]:
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
另一个滤除DataFrame行的问题涉及时间序列数据。假设你只想留下一部分观测数据,可以用 thresh
参数实现此目的
In [25]: df = pd.DataFrame(np.random.randn(7, 3))
In [26]: df.iloc[:4, 1] = NA
In [27]: df.iloc[:2, 2] = NA
In [28]: df
Out[28]:
0 1 2
0 1.279066 NaN NaN
1 -0.037111 NaN NaN
2 -1.102988 NaN 1.282095
3 0.678465 NaN -0.244893
4 0.936922 -0.433543 0.501408
5 1.808474 -0.140179 -0.923943
6 -0.095324 -0.555709 -0.346352
In [29]: df.dropna()
Out[29]:
0 1 2
4 0.936922 -0.433543 0.501408
5 1.808474 -0.140179 -0.923943
6 -0.095324 -0.555709 -0.346352
In [30]: df.dropna(thresh=2)
Out[30]:
0 1 2
2 -1.102988 NaN 1.282095
3 0.678465 NaN -0.244893
4 0.936922 -0.433543 0.501408
5 1.808474 -0.140179 -0.923943
6 -0.095324 -0.555709 -0.346352
填充缺失数据
你可能不想滤除缺失数据(有可能会丢弃跟它有关的其他数据),而是希望通过其他方式填补那些“空洞”。 对于大多数情况而言,fillna()
方法是最主要的函数。通过一个常数调用fillna()
就会将缺失值替换为那个常数值
In [31]: df.fillna(0)
Out[31]:
0 1 2
0 1.279066 0.000000 0.000000
1 -0.037111 0.000000 0.000000
2 -1.102988 0.000000 1.282095
3 0.678465 0.000000 -0.244893
4 0.936922 -0.433543 0.501408
5 1.808474 -0.140179 -0.923943
6 -0.095324 -0.555709 -0.346352
若是通过一个字典调用 fillna()
,就可以实现对不同的列填充不同的值
In [32]: df.fillna({1: 0.5, 2: 0})
Out[32]:
0 1 2
0 1.279066 0.500000 0.000000
1 -0.037111 0.500000 0.000000
2 -1.102988 0.500000 1.282095
3 0.678465 0.500000 -0.244893
4 0.936922 -0.433543 0.501408
5 1.808474 -0.140179 -0.923943
6 -0.095324 -0.555709 -0.346352
fillna()
默认会返回新对象,但也可以对现有对象进行就地修改
In [33]: df.fillna(0, inplace=True)
In [34]: df
Out[34]:
0 1 2
0 1.279066 0.000000 0.000000
1 -0.037111 0.000000 0.000000
2 -1.102988 0.000000 1.282095
3 0.678465 0.000000 -0.244893
4 0.936922 -0.433543 0.501408
5 1.808474 -0.140179 -0.923943
6 -0.095324 -0.555709 -0.346352
对reindexing有效的那些插值方法也可用于 fillna()
In [39]: df.fillna(method='ffill')
Out[39]:
0 1 2
0 -0.892430 1.354326 1.183773
1 -0.358144 0.256747 0.309020
2 0.107312 0.256747 -0.017276
3 -0.643787 0.256747 -0.476113
4 0.709494 0.256747 -0.476113
5 -1.062814 0.256747 -0.476113
In [40]: df.fillna(method='ffill', limit=2)
Out[40]:
0 1 2
0 -0.892430 1.354326 1.183773
1 -0.358144 0.256747 0.309020
2 0.107312 0.256747 -0.017276
3 -0.643787 0.256747 -0.476113
4 0.709494 NaN -0.476113
5 -1.062814 NaN -0.476113
只要有些创新,你就可以利用fillna()
实现许多别的功能。比如说,你可以传入Series的平均值或中位数
In [41]: data = pd.Series([1., NA, 3.5, NA, 7])
In [42]: data.fillna(data.mean())
Out[42]:
0 1.000000
1 3.833333
2 3.500000
3 3.833333
4 7.000000
dtype: float64