Pandas缺失值处理

直观上理解,缺失值表示的是“缺失的数据”。

更多:Pandas

Pandas基本功能详解 介绍了 Pandas 中常用的一些功能,使得我们对 Pandas 的使用有了基本的了解。这一章节我们来看下如何使用Pandas处理缺失值。

# 导入相关库
import numpy as np
import pandas as pd
什么是缺失值

在了解缺失值(也叫控制)如何处理之前,首先要知道的就是什么是缺失值?直观上理解,缺失值表示的是“缺失的数据”

可以思考一个问题:是什么原因造成的缺失值呢?其实有很多原因,实际生活中可能由于有的数据不全所以导致数据缺失,也有可能由于误操作导致数据缺失,又或者人为地造成数据缺失。

来看下我们的示例吧。

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-08-08", np.nan, "1988-10-17"]
}

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

# 将出生日期转为时间戳
user_info["birth"] = pd.to_datetime(user_info.birth)
user_info
agebirthcitysex
name
Tom18.02000-02-10BeiJingNone
Bob30.01988-10-17ShangHaimale
MaryNaNNaTGuangZhoufemale
James40.01978-08-08ShenZhenmale
AndyNaNNaTNaNNaN
Alice30.01988-10-17unknown

可以看到,用户 Tom 的性别为 None,用户 Mary 的年龄为 NAN,生日为 NaT。在 Pandas 的眼中,这些都属于缺失值,可以使用 isnull()notnull() 方法来操作。

user_info.isnull()
agebirthcitysex
name
TomFalseFalseFalseTrue
BobFalseFalseFalseFalse
MaryTrueTrueFalseFalse
JamesFalseFalseFalseFalse
AndyTrueTrueTrueTrue
AliceFalseFalseFalseFalse

除了简单的可以识别出哪些是缺失值或非缺失值外,最常用的就是过滤掉一些缺失的行。比如,我想过滤掉用户年龄为空的用户,如何操作呢?

user_info[user_info.age.notnull()]
agebirthcitysex
name
Tom18.02000-02-10BeiJingNone
Bob30.01988-10-17ShangHaimale
James40.01978-08-08ShenZhenmale
Alice30.01988-10-17unknown
丢弃缺失值

既然有缺失值了,常见的一种处理办法就是丢弃缺失值。使用 dropna 方法可以丢弃缺失值。

user_info.age.dropna()
name
Tom      18.0
Bob      30.0
James    40.0
Alice    30.0
Name: age, dtype: float64

Seriese 使用 dropna 比较简单,对于 DataFrame 来说,可以设置更多的参数。

axis 参数用于控制行或列,跟其他不一样的是,axis=0 (默认)表示操作行,axis=1 表示操作列。

how 参数可选的值为 any(默认) 或者 allany 表示一行/列有任意元素为空时即丢弃,all 一行/列所有值都为空时才丢弃。

subset 参数表示删除时只考虑的索引或列名。

thresh参数的类型为整数,它的作用是,比如 thresh=3,会在一行/列中至少有 3 个非空值时将其保留。

# 一行数据只要有一个字段存在空值即删除
user_info.dropna(axis=0, how="any")
agebirthcitysex
name
Bob30.01988-10-17ShangHaimale
James40.01978-08-08ShenZhenmale
Alice30.01988-10-17unknown
# 一行数据所有字段都为空值才删除
user_info.dropna(axis=0, how="all")
agebirthcitysex
name
Tom18.02000-02-10BeiJingNone
Bob30.01988-10-17ShangHaimale
MaryNaNNaTGuangZhoufemale
James40.01978-08-08ShenZhenmale
Alice30.01988-10-17unknown
# 一行数据中只要 city 或 sex 存在空值即删除
user_info.dropna(axis=0, how="any", subset=["city", "sex"])
agebirthcitysex
name
Bob30.01988-10-17ShangHaimale
MaryNaNNaTGuangZhoufemale
James40.01978-08-08ShenZhenmale
Alice30.01988-10-17unknown
填充缺失值

除了可以丢弃缺失值外,也可以填充缺失值,最常见的是使用 fillna 完成填充。

fillna 这名字一看就是用来填充缺失值的。

填充缺失值时,常见的一种方式是使用一个标量来填充。例如,这里我样有缺失的年龄都填充为 0。

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' 可以使用前一个有效值来填充。

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

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

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

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

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 的眼中是缺失值,有时候在我们人类的眼中,某些异常值我们也会当做缺失值来处理。

例如,在我们的存储的用户信息中,假定我们限定用户都是青年,出现了年龄为 40 的,我们就可以认为这是一个异常值。再比如,我们都知道性别分为男性(male)和女性(female),在记录用户性别的时候,对于未知的用户性别都记为了 “unknown”,很明显,我们也可以认为“unknown”是缺失值。此外,有的时候会出现空白字符串,这些也可以认为是缺失值。

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

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

也可以指定一个映射字典。

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

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

user_info.replace({"age": 40, "birth": pd.Timestamp("1978-08-08")}, np.nan)
agebirthcitysex
name
Tom18.02000-02-10BeiJingNone
Bob30.01988-10-17ShangHaimale
MaryNaNNaTGuangZhoufemale
JamesNaNNaTShenZhenmale
AndyNaNNaTNaNNaN
Alice30.01988-10-17unknown

类似地,我们可以将特定字符串进行替换,如:将 “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

除了可以替换特定的值之外,还可以使用正则表达式来替换,如:将空白字符串替换成空值。

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 中的元素传给有缺失值的。

age_new = user_info.age.copy()
age_new.fillna(20, inplace=True)
age_new
name
Tom      18.0
Bob      30.0
Mary     20.0
James    40.0
Andy     20.0
Alice    30.0
Name: age, dtype: float64
user_info.age.combine_first(age_new)
name
Tom      18.0
Bob      30.0
Mary     20.0
James    40.0
Andy     20.0
Alice    30.0
Name: age, dtype: float64

可以看到,用户信息中关于年龄的缺失值都使用 age_new 这个 Series 填充了。

发表评论

电子邮件地址不会被公开。 必填项已用*标注