2020-08-05--Pandas-03--缺失值處理

這一章節(jié)我們來看下如何使用Pandas處理缺失值。

什么是缺失值

在了解缺失值(也叫控制)如何處理之前,首先要知道的就是什么是缺失值?直觀上理解,缺失值表示的是“缺失的數(shù)據(jù)”。

可以思考一個問題:是什么原因造成的缺失值呢?其實有很多原因,實際生活中可能由于有的數(shù)據(jù)不全所以導致數(shù)據(jù)缺失,也有可能由于誤操作導致數(shù)據(jù)缺失,又或者人為地造成數(shù)據(jù)缺失。

來看下我們的示例吧。

import pandas as pd
import numpy as np

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)

# 將出生日期轉(zhuǎn)為時間戳
user_info["birth"] = pd.to_datetime(user_info.birth)

print(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-1

可以看到,用戶 Tom 的性別為 None,用戶 Mary 的年齡為 NAN,生日為 NaT。在 Pandas 的眼中,這些都屬于缺失值,可以使用 isnull() 或 notnull() 方法來操作。

1.isnull() 和 notnull()

isnull針對DataFrame對象,notnull()針對Series對象

isnull():判斷數(shù)據(jù)中的缺失值,若是確實值,則為True,否則為Flase,返回一個具體數(shù)據(jù)權(quán)威bool值的DataFrame對象

# isnull():判斷數(shù)據(jù)中的缺失值,若是確實值,則為True,否則為Flase,返回一個具體數(shù)據(jù)權(quán)威bool值的DataFrame對象
isnull = user_info.isnull()
print(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

除了簡單的可以識別出哪些是缺失值或非缺失值外,最常用的就是過濾掉一些缺失的行。比如,我想過濾掉用戶年齡為空的用戶,如何操作呢?

notnull():查看每行的該值是否為確實值,若是,則為True,否則為False,返回Series對象。

print(user_info.age.notnull())
# name
# Tom       True
# Bob       True
# Mary     False
# James     True
# Andy     False
# Alice     True
# Name: age, dtype: bool

# 過濾掉age為空的行后的數(shù)據(jù)
notnull = user_info[user_info.age.notnull()]
print(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-17

丟棄缺失值

dropna()

對于Series對象,相對簡單,直接刪除對應值為缺失值的行,返回刪除后的數(shù)據(jù)(Series對象)

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

對于DataFrame對象,相對復雜,因為刪除要謹慎操作,參數(shù)有:

  • axis參數(shù)用于控制行或列,跟其他不一樣的是,axis=0 (默認)表示操作行,axis=1 表示操作列。
  • how 參數(shù)可選的值為 any(默認) 或者 all。any 表示一行/列有任意元素為空時即丟棄,all 一行/列所有值都為空時才丟棄。
  • subset 參數(shù)為列表,列表項為索引或列名,表示刪除時只根據(jù)給出索引或列名是否為缺失值來刪除對應的數(shù)據(jù)。
  • thresh參數(shù)的類型為整數(shù),它的作用是某行缺失值數(shù)量是否刪除的標準,比如 thresh=3,會在一行/列中至少有 3 個非空值時將其保留。
print(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-17

# 刪除所有列都為空數(shù)據(jù)的那一行
c = user_info.dropna(axis=0,how='all')
print(c)
#         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-17

# 刪除age或者city列為空的那行的整條數(shù)據(jù)
c = user_info.dropna(axis=0,subset=['age','city'])
print(c)
#         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-17

# 刪除有空值的行
c = user_info.dropna(axis=0,how='any')
print(c)
#         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-17


# 刪除空值在2個以上的行
c = user_info.dropna(axis=0,how='any',thresh=2)
print(c)
#         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-17

填充缺失值

除了可以丟棄缺失值外,也可以填充缺失值,最常見的是使用 fillna 完成填充。

fillna 這名字一看就是用來填充缺失值的。

填充缺失值時,常見的一種方式是使用一個標量來填充。例如,這里我樣有缺失的年齡都填充為 0。

fillna()

# 對于Series對象來說的fillna()
c = user_info.age.fillna(0)
print(user_info)
print(c)
# name
# Tom      18.0
# Bob      30.0
# Mary      0.0
# James    40.0
# Andy      0.0
# Alice    30.0
# Name: age, dtype: float64

除了可以使用標量來填充之外,還可以使用前一個或后一個有效值來填充。

設置參數(shù) method='pad' 或 method='ffill' 可以使用前一個有效值來填充。

# 用前一行的該列的值進行填充
c = user_info.age.fillna(method="ffill")
print(c)
# name
# Tom      18.0
# Bob      30.0
# Mary     30.0
# James    40.0
# Andy     40.0
# Alice    30.0
# Name: age, dtype: float64

設置參數(shù) method='bfill' 或 method='backfill' 可以使用后一個有效值來填充。

# 用后一行的該列的值進行填充
c= user_info.age.fillna(method="backfill")
print(c)
# name
# Tom      18.0
# Bob      30.0
# Mary     40.0
# James    40.0
# Andy     30.0
# Alice    30.0
# Name: age, dtype: float64

對于DataFrame來說,該方法使用與Series一樣,只是填充的數(shù)據(jù)多了而已

注意:在對Series進行修改或填充時,默認時不會對原數(shù)據(jù)對象修改的,可以在修改,填充,刪除的方法的參數(shù)中加上inplace=True,那么這時就不會有返回值了,再次打印原數(shù)據(jù)時,就會發(fā)生改變
實例:
對DataFrame對象中的age列每一項都填充0,其他不變。

user_info.age.fillna(0,inplace=True)
print(user_info)
#         age       city      sex      birth
# name                                      
# Tom    18.0    BeiJing     None 2000-02-10
# Bob    30.0   ShangHai     male 1988-10-17
# Mary    0.0  GuangZhou   female        NaT
# James  40.0   ShenZhen     male 1978-08-08
# Andy    0.0        NaN      NaN        NaT
# Alice  30.0             unknown 1988-10-17

interpolate()

除了通過 fillna 方法來填充缺失值外,還可以通過 interpolate 方法來填充。默認情況下使用線性差值,可以是設置 method 參數(shù)來改變方式。

# 使用線性差值進行填充
c = user_info.age.interpolate()
print(c)
# name
# Tom      18.0
# Bob      30.0
# Mary     35.0
# James    40.0
# Andy     35.0
# Alice    30.0
# Name: age, dtype: float64 

替換缺失值

大家有沒有想過一個問題:到底什么才是缺失值呢?你可能會奇怪說,前面不是已經(jīng)說過了么,None、np.nan、NaT 這些都是缺失值。但是我也說過了,這些在 Pandas 的眼中是缺失值,有時候在我們?nèi)祟惖难壑校承┊惓V滴覀円矔斪鋈笔е祦硖幚怼?/p>

例如,在我們的存儲的用戶信息中,假定我們限定用戶都是青年,出現(xiàn)了年齡為 40 的,我們就可以認為這是一個異常值。再比如,我們都知道性別分為男性(male)和女性(female),在記錄用戶性別的時候,對于未知的用戶性別都記為了 “unknown”,很明顯,我們也可以認為“unknown”是缺失值。此外,有的時候會出現(xiàn)空白字符串,這些也可以認為是缺失值。

replace()

對于上面的這種情況,我們可以使用 replace 方法來替換缺失值。
對于Series對象

# 將age列的np.nan數(shù)據(jù)項替換為50
c = user_info.age.replace(np.nan,50)
print(c)
# name
# Tom      18.0
# Bob      30.0
# Mary     50.0
# James    40.0
# Andy     50.0
# Alice    30.0
# Name: age, dtype: float64

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

c = user_info.age.replace({np.nan:50})
print(c)
# name
# Tom      18.0
# Bob      30.0
# Mary     50.0
# James    40.0
# Andy     50.0
# Alice    30.0
# Name: age, dtype: float64

對于DataFrame來說,可以在replace方法中加上參數(shù)inplace=True來做原地操作:可以對DataFrame,也可以針對某一列/行(Series):

# 將數(shù)據(jù)中所有的NaN替換為50
user_info.replace(np.nan,50,inplace=True)
print(user_info)
#         age       city      sex         birth
# name
# Tom    18.0    BeiJing       50  9.501408e+17
# Bob    30.0   ShangHai     male  5.930496e+17
# Mary   50.0  GuangZhou   female  5.000000e+01
# James  40.0   ShenZhen     male  2.713824e+17
# Andy   50.0         50       50  5.000000e+01
# Alice  30.0             unknown  5.930496e+17

# 將數(shù)據(jù)中的age列的59替換為NaN
user_info.age.replace(50,np.nan,inplace=True)
print(user_info)
#         age       city      sex         birth
# name                                         
# Tom    18.0    BeiJing       50  9.501408e+17
# Bob    30.0   ShangHai     male  5.930496e+17
# Mary    NaN  GuangZhou   female  5.000000e+01
# James  40.0   ShenZhen     male  2.713824e+17
# Andy    NaN         50       50  5.000000e+01
# Alice  30.0             unknown  5.930496e+17

可以指定每列要替換的值。設置為原地操作

# 替換多個值
user_info.replace({"age": 40, "birth": pd.Timestamp("1978-08-08")}, np.nan,inplace=True)
print(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   NaN   ShenZhen     male        NaT
# Andy    NaN        NaN      NaN        NaT
# Alice  30.0             unknown 1988-10-17

類似地,我們可以將特定字符串進行替換.

除了可以替換特定的值之外,還可以使用正則表達式來替換,如:將空白字符串替換成空值。

user_info.city.replace(r'\s+', np.nan, regex=True,inplace=True)
print(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        NaN  unknown 1988-10-17

使用對象填充

除了我們自己手動丟棄、填充已經(jīng)替換缺失值之外,我們還可以使用對象來填充。

例如有兩個關(guān)于用戶年齡的 Series,其中一個有缺失值,另一個沒有,我們可以將沒有的缺失值的 Series 中的元素傳給有缺失值的。

對于Series:

# 數(shù)據(jù)完整的Series對象a
a = user_info.age
a.fillna(50,inplace=True)
print(a)
# name
# Tom      18.0
# Bob      30.0
# Mary     50.0
# James    40.0
# Andy     50.0
# Alice    30.0
# Name: age, dtype: float64

# 有缺失值的Series對象b
name = pd.Index(["Tom", "Bob", "Mary", "James"], name="name")
b = pd.Series(data=[18, 30, 25, np.nan], index=name, name="user_age_info")
print(b)
# name
# Tom      18.0
# Bob      30.0
# Mary     25.0
# James     NaN
# Name: user_age_info, dtype: float64

# 將a中的數(shù)據(jù)替換到b中
b = b.combine_first(a)
print(b)
# name
# Alice    30.0
# Andy     50.0
# Bob      30.0
# James    40.0
# Mary     25.0
# Tom      18.0
# Name: user_age_info, dtype: float64

對于DataFrame,與Series一樣。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容