1. 程式人生 > >Pandas缺失值處理 | 輕鬆玩轉Pandas(3)

Pandas缺失值處理 | 輕鬆玩轉Pandas(3)

轉自:http://www.naodongopen.com/997.html

# 匯入相關庫
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 填充了。