Pandas(三)

Pandas 学习系列(三)

缺失值处理

1
2
import numpy as np
import pandas as pd

如何处理

  • 丢弃
  • 填充
  • 替换
  • 使用其他对象填充
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 示例数据
index = pd.Index(data=['Tom', 'Bob', 'Mary', 'James', 'Andy', 'Alice'], name='name')

data = {
'age': [18, 30, np.nan, 40, np.nan, 30],
'city': ['Beijing', 'Shanghai', 'Guangzhou', 'Shenzhen', np.nan, ' '],
'sex': [None, 'male', 'female', 'male', np.nan, 'unknown'],
'birth': ['2000-02-10', '1988-10-17', None, '1978-8-8', np.nan, '1988-10-11']
}

user_info = pd.DataFrame(data=data, index=index)

# 将出生日期转化为时间戳
user_info['birth'] = pd.to_datetime(user_info.birth)

user_info
age city sex birth
name
Tom 18.0 Beijing None 2000-02-10
Bob 30.0 Shanghai male 1988-10-17
Mary NaN Guangzhou female NaT
James 40.0 Shenzhen male 1978-08-08
Andy NaN NaN NaN NaT
Alice 30.0 unknown 1988-10-11

上面数据中,Tom、Mary 的数据都有缺失,可以使用 isnull()notnull() 方法来查找:

1
user_info.isnull()
age city sex birth
name
Tom False False True False
Bob False False False False
Mary True False False True
James False False False False
Andy True True True True
Alice False False False False

除了简单的查找识别哪些数据是缺失的,还可以有其他的一些操作,比如过滤掉用户年龄为空的用户:

1
user_info[user_info.age.notnull()]
age city sex birth
name
Tom 18.0 Beijing None 2000-02-10
Bob 30.0 Shanghai male 1988-10-17
James 40.0 Shenzhen male 1978-08-08
Alice 30.0 unknown 1988-10-11

丢弃

使用 dropna 方法丢弃缺失值:

1
user_info
age city sex birth
name
Tom 18.0 Beijing None 2000-02-10
Bob 30.0 Shanghai male 1988-10-17
Mary NaN Guangzhou female NaT
James 40.0 Shenzhen male 1978-08-08
Andy NaN NaN NaN NaT
Alice 30.0 unknown 1988-10-11
1
clean_age = user_info.age.dropna()
1
clean_age
name
Tom      18.0
Bob      30.0
James    40.0
Alice    30.0
Name: age, dtype: float64

Series 的 dropna() 比较简单,对于 DataFrame 来说,可以设置更多的参数。

  • axis 参数,控制行或列,axis=0(默认)表示操作行,axis=1 表示操作列。
  • how 参数,丢弃哪些数据,可选参数:any(默认)或者 allany 表示一行/列有任意元素为空就丢弃,all 一行/列所有值都为空,才丢弃。
  • subset 参数,表示删除时只考虑索引或列名。
  • thresh 参数,阈值,表示有几个实际值以后就不删除,比如 thresh=3 一行/列非空值大于 3 个就将其保留。
1
2
# 一行数据只要有一个字段存在空值就删除
user_info.dropna(axis=0, how='any')
age city sex birth
name
Bob 30.0 Shanghai male 1988-10-17
James 40.0 Shenzhen male 1978-08-08
Alice 30.0 unknown 1988-10-11
1
2
# 一行数据所有字段都为空才删除
user_info.dropna(axis=0, how='all')
age city sex birth
name
Tom 18.0 Beijing None 2000-02-10
Bob 30.0 Shanghai male 1988-10-17
Mary NaN Guangzhou female NaT
James 40.0 Shenzhen male 1978-08-08
Alice 30.0 unknown 1988-10-11
1
2
# city 或 sex 存在空值即删除
user_info.dropna(axis=0, how='any', subset=['city', 'sex'])
age city sex birth
name
Bob 30.0 Shanghai male 1988-10-17
Mary NaN Guangzhou female NaT
James 40.0 Shenzhen male 1978-08-08
Alice 30.0 unknown 1988-10-11
1
2
# 要有三个即以上实际值就不删除
user_info.dropna(axis=0, thresh=3)
age city sex birth
name
Tom 18.0 Beijing None 2000-02-10
Bob 30.0 Shanghai male 1988-10-17
James 40.0 Shenzhen male 1978-08-08
Alice 30.0 unknown 1988-10-11

填充缺失值

最常见的就是使用 fillna 完成填充。

常见的填充方式是使用一个标量来填充。例如,将所有缺失的年龄都填充为 0:

1
user_info.age.fillna(0)
name
Tom      18.0
Bob      30.0
Mary      0.0
James    40.0
Andy      0.0
Alice    30.0
Name: age, dtype: float64

除了使用标量来填充,使用前一个或后一个的有效值来填充。

设置参数 method='pad' 或者 method='ffill' 可以使用前一个 有效值 来填充:

1
user_info.age.fillna(method='ffill')
name
Tom      18.0
Bob      30.0
Mary     30.0
James    40.0
Andy     40.0
Alice    30.0
Name: age, dtype: float64
1
user_info.age.fillna(method='pad')
name
Tom      18.0
Bob      30.0
Mary     30.0
James    40.0
Andy     40.0
Alice    30.0
Name: age, dtype: float64

设置参数 method='bfill' 或者 method='backfill' 可以使用后一个 有效值 来填充:

1
user_info.age.fillna(method='backfill')
name
Tom      18.0
Bob      30.0
Mary     40.0
James    40.0
Andy     30.0
Alice    30.0
Name: age, dtype: float64
1
user_info.age.fillna(method='bfill')
name
Tom      18.0
Bob      30.0
Mary     40.0
James    40.0
Andy     30.0
Alice    30.0
Name: age, dtype: float64

除了通过 fillna 方法来填充缺失值外,还可以通过 interpolate 方法来填充。默认情况下使用线性差值,可以设置 method 参数来改变方式:

1
user_info.age
name
Tom      18.0
Bob      30.0
Mary      NaN
James    40.0
Andy      NaN
Alice    30.0
Name: age, dtype: float64
1
user_info.age.interpolate()
name
Tom      18.0
Bob      30.0
Mary     35.0
James    40.0
Andy     35.0
Alice    30.0
Name: age, dtype: float64

替换缺失值

Nonenp.nanNaT 这些值,Pandas 眼中都是缺失值,但在人类眼中,某些异常值我们都会当做缺失值来处理。

比如:我们的表里面记录的都是青年人,但如果某个年龄数据超过了 35 岁,那肯定是个异常值。另外,如果性别记录出现 ‘unknown’,肯定也是异常值。

对于以上这种情况,我们可以使用 replace 方法来替换缺失值:

1
2
# 年龄 40 岁替换成 np.nan
user_info.age.replace(40, np.nan)
name
Tom      18.0
Bob      30.0
Mary      NaN
James     NaN
Andy      NaN
Alice    30.0
Name: age, dtype: float64

替换值也可以是一个字段:

1
2
# 年龄 18 岁替换成 np.nan
user_info.age.replace({18: np.nan})
name
Tom       NaN
Bob      30.0
Mary      NaN
James    40.0
Andy      NaN
Alice    30.0
Name: age, dtype: float64

对于 DataFrame,可以指定每列要替换的值:

1
user_info
age city sex birth
name
Tom 18.0 Beijing None 2000-02-10
Bob 30.0 Shanghai male 1988-10-17
Mary NaN Guangzhou female NaT
James 40.0 Shenzhen male 1978-08-08
Andy NaN NaN NaN NaT
Alice 30.0 unknown 1988-10-11
1
user_info.replace({'age': 40, 'birth': pd.Timestamp('1978-8-8')}, np.nan)
age city sex birth
name
Tom 18.0 Beijing None 2000-02-10
Bob 30.0 Shanghai male 1988-10-17
Mary NaN Guangzhou female NaT
James NaN Shenzhen male NaT
Andy NaN NaN NaN NaT
Alice 30.0 unknown 1988-10-11

还可以将特定字符串进行替换:

1
2
# 将 unknown 进行替换
user_info.sex.replace('unknown', np.nan)
name
Tom        None
Bob        male
Mary     female
James      male
Andy        NaN
Alice       NaN
Name: sex, dtype: object

替换还可以使用正则来替换:

1
user_info.city
name
Tom        Beijing
Bob       Shanghai
Mary     Guangzhou
James     Shenzhen
Andy           NaN
Alice             
Name: city, dtype: object
1
2
# 将空白字符串替换成空值
user_info.city.replace(r'\s+', np.nan, regex=True)
name
Tom        Beijing
Bob       Shanghai
Mary     Guangzhou
James     Shenzhen
Andy           NaN
Alice          NaN
Name: city, dtype: object

使用其他对象填充

我们可以把一个有值的 Series 数据填充给另一个有缺失值的 Series:

1
2
3
4
5
new_age = user_info.age.copy()
new_age.fillna(20, inplace=True)

new_age['Tom'] = 55
new_age
name
Tom      55.0
Bob      30.0
Mary     20.0
James    40.0
Andy     20.0
Alice    30.0
Name: age, dtype: float64
1
user_info.age.combine_first(new_age)
name
Tom      18.0
Bob      30.0
Mary     20.0
James    40.0
Andy     20.0
Alice    30.0
Name: age, dtype: float64

可见,有缺失值的 Series 被有数据的 Series 做了填充。