First Score | Second Score | Third Score | |
---|---|---|---|
0 | 100 | 30 | |
1 | 90 | 45 | 40 |
2 | 56 | 80 | |
3 | 95 | 98 |
在普遍的办公场景下(尤其是一些重要的表格),通常都有可能是有特殊的情况,那么此时都一定会去手动修改,甚至有时还会特别麻烦(比如银行的某些信息)。但我们在竞赛中,研究中,做项目的过程中对这些数据就可以自由一点,希望能利用经验知识等来对它们进行一定的处理。
本文就从这类问题入手讲解一下在Pandas中如何处理这些数据。
据官方文档描述,由于在Python中None
就是默认的空值类型,因此它首先就会被当作缺失数据处理。
其次Nan
(not a number)也是常见的空值或者异常数据类型。
同时,官网说道:+-inf
也可以被视作缺失数据,此时需要加设一句:
pandas.options.mode.use_inf_as_na = True
比如上面的数据如果以逗号分隔存入csv
文件,再读取出来时是这样:
df = pd.read_csv(r".\test_nan.csv") # 数据存在该文件中
df
Unnamed: 0 First Score Second Score Third Score
0 0 100.0 30.0 NaN
1 1 90.0 45.0 40.0
2 2 NaN 56.0 80.0
3 3 95.0 NaN 98.0
这里显示的第一列是Index
,第二列Unnamed:0
是由于这一个位置是空,于是被自动命名为"未命名"表头。而这里我们能清楚地看到,表中的空行已经被显示为NaN
。
不过要注意的是,此时如果
csv
文件中这些空值位置是空格或者Tab的话,它会被识别为’ ‘或者’ '。如果不明白就复制引号中的内容,再粘贴到word里面自然就清楚了。
Pandas中提供了判断表中数据是否为缺失数据的方法isnull
:
df.isnull()
Unnamed: 0 First Score Second Score Third Score
0 False False False True
1 False False False False
2 False True False False
3 False False True False
这里可以看到,所有NaN
的位置全部变成了True
。但光是这样其实还远不够,尤其当数据量较大时,我们其实更想的是如果准确地定位这些数据,再想办法对其进行修改。
当然我们常规的思路是想直接定位到它的行列值上,这样就最方便,但Pandas并没有提供这样的一种方法,非常可惜。于是我们只能选择退而求其次的方案。
首先,我们可以先简单统计一下上哪些列有空值:
df.isnull().sum()
Unnamed: 0 0
First Score 1
Second Score 1
Third Score 1
dtype: int64
这个原理就很简单了,由于df.isnull()
函数返回的表中每列全是Bool
类型,而sum()
是针对数值的操作,默认就将Ture
和False
转为1和0。那么对每列数据求和自然就统计出了缺失的数据总量。
其次,可以考虑直接从DataFrame
的值入手,获取缺失数据在其数据主体中所在的位置。
np.argwhere(np.isnan(df.values))
array([[0, 3],
[2, 1],
[3, 2]], dtype=int64)
%timeit np.argwhere(np.isnan(df.values))
53.8 µs ± 68.1 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
这里是借助Numpy中的定位函数,也比较简单,运行的时间也没有想象中那么慢。
此时返回的数组中,第一个元素就是行数,第二个元素就是列所在的位置(也从0开始),那么也很容易找到它们对应的列名:
for i,j in np.argwhere(np.isnan(df.values)):
print('The',j,'th Column name:',df.iloc[:,j].name)
The 3 th Column name: Third Score
The 1 th Column name: First Score
The 2 th Column name: Second Score
当然,还有更为高明的方法,可以参考Pandas缺失数据最快定位方式(极少代码快速实现,打死不用循环!!!)
能够精准定位数据,自然也就可以对其进行修改了。最简单的方式自然是给出每个位置应有的值,比如:
df.iloc[2, 1] = 32
当然,这种方式与手动修改无异。我们想要看的是一些简单暴力而又常用的方法。
fillna()
比如我想将所有异常数据用一种夸张的形式填充:
df.fillna("!*#^@")
Unnamed: 0 First Score Second Score Third Score
0 0 100 30 !*#^@
1 1 90 45 40
2 2 !*#^@ 56 80
3 3 95 !*#^@ 98
那么自然地,也可以用一些固定的数值来填充,比如:
df.fillna(-1)
Unnamed: 0 First Score Second Score Third Score
0 0 100.0 30.0 -1.0
1 1 90.0 45.0 40.0
2 2 -1.0 56.0 80.0
3 3 95.0 -1.0 98.0
这里注意到,fillna()
中可以填充的类型是任意的,只要可以作为数据的东西都可以放进去,甚至包括Pandas的object. 这里就不再赘述,其实不用看官方文档也能很容易试出来。
df.fillna(method='pad')
Out[154]:
Unnamed: 0 First Score Second Score Third Score
0 0 100.0 30.0 NaN
1 1 90.0 45.0 40.0
2 2 90.0 56.0 80.0
3 3 95.0 56.0 98.0
df.fillna(method='bfill')
Out[155]:
Unnamed: 0 First Score Second Score Third Score
0 0 100.0 30.0 40.0
1 1 90.0 45.0 40.0
2 2 95.0 56.0 80.0
3 3 95.0 NaN 98.0
另外还可对填充次数进行限制,比如只允许填充一次:
df.fillna(method='bfill',limit=1)
这里由于每列数据只有一个空值,因此与上面的代码结果无异。
interpolate
)可以看到上面缺失的数据都是数值,那么此时我们可以用插值的方式来处理,这种方式尤其在数据本身平稳并且量较充足的时候非常有用。同时也很自然地想到,这种操作对于我们参加数据挖掘竞赛非常有利!
df.interpolate(method='linear')
Unnamed: 0 First Score Second Score Third Score
0 0 100.0 30.0 NaN
1 1 90.0 45.0 40.0
2 2 92.5 56.0 80.0
3 3 95.0 56.0 98.0
这里可以看到,多数空值都被填充了。它的原理是对现有的点进行线性插值,从而达到数据填充的目的。
另外,细心的同学应该也发现了,这里第一行最后一列数据并未被修改,这是因为默认的插值法是向前插值(即向下面的行进行插值),那么这里稍作修改即可:
df.interpolate(method='linear',limit_direction='backward')
Out[166]:
Unnamed: 0 First Score Second Score Third Score
0 0 100.0 30.0 40.0
1 1 90.0 45.0 40.0
2 2 92.5 56.0 80.0
3 3 95.0 NaN 98.0
如果上下都想用,就用两次即可:
df.interpolate(method='linear',limit_direction='backward').interpolate(method='linear',limit_direction='forward')
Unnamed: 0 First Score Second Score Third Score
0 0 100.0 30.0 40.0
1 1 90.0 45.0 40.0
2 2 92.5 56.0 80.0
3 3 95.0 56.0 98.0
注:Pandas在实现这类方法时实际上是调用的
scipy
的库,因此需要提前将scipy
装好。
当然,插值的方法有很多,目前该方法提供的选择如下:
df.interpolate(method='polynomial', order=5)
.scipy.interpolate.BPoly.from_derivatives
关于上述所有方法的说明可以直接参考scipy
的文档或者用户说明。
一、Pandas简介与安装
二、Pandas基本数据结构-DataFrame与Series
三、Pandas文件读写
四、Pandas数据索引方式
五、Pandas简单统计操作及通用方式
六、Pandas条件查询
七、Pandas缺失数据的处理(数据清洗基础)
八、Pandas数据透视表
九、表的合并、连接、拼接(数据聚合基础)