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

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

什么是缺失值

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

可以思考一個(gè)問(wèn)題:是什么原因造成的缺失值呢浇垦?其實(shí)有很多原因炕置,實(shí)際生活中可能由于有的數(shù)據(jù)不全所以導(dǎo)致數(shù)據(jù)缺失,也有可能由于誤操作導(dǎo)致數(shù)據(jù)缺失男韧,又或者人為地造成數(shù)據(jù)缺失朴摊。

來(lái)看下我們的示例吧。

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)為時(shí)間戳
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() 方法來(lái)操作。

1.isnull() 和 notnull()

isnull針對(duì)DataFrame對(duì)象春哨,notnull()針對(duì)Series對(duì)象

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

# isnull():判斷數(shù)據(jù)中的缺失值,若是確實(shí)值臭胜,則為True,否則為Flase癞尚,返回一個(gè)具體數(shù)據(jù)權(quán)威bool值的DataFrame對(duì)象
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

除了簡(jiǎn)單的可以識(shí)別出哪些是缺失值或非缺失值外耸三,最常用的就是過(guò)濾掉一些缺失的行。比如浇揩,我想過(guò)濾掉用戶年齡為空的用戶仪壮,如何操作呢?

notnull():查看每行的該值是否為確實(shí)值胳徽,若是积锅,則為True,否則為False养盗,返回Series對(duì)象缚陷。

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

# 過(guò)濾掉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()

對(duì)于Series對(duì)象,相對(duì)簡(jiǎn)單往核,直接刪除對(duì)應(yīng)值為缺失值的行,返回刪除后的數(shù)據(jù)(Series對(duì)象)

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

對(duì)于DataFrame對(duì)象箫爷,相對(duì)復(fù)雜,因?yàn)閯h除要謹(jǐn)慎操作,參數(shù)有:

  • axis參數(shù)用于控制行或列聂儒,跟其他不一樣的是虎锚,axis=0 (默認(rèn))表示操作行生兆,axis=1 表示操作列屠凶。
  • how 參數(shù)可選的值為 any(默認(rèn)) 或者 all。any 表示一行/列有任意元素為空時(shí)即丟棄买羞,all 一行/列所有值都為空時(shí)才丟棄非春。
  • subset 參數(shù)為列表柱徙,列表項(xiàng)為索引或列名,表示刪除時(shí)只根據(jù)給出索引或列名是否為缺失值來(lái)刪除對(duì)應(yīng)的數(shù)據(jù)奇昙。
  • thresh參數(shù)的類型為整數(shù)坐搔,它的作用是某行缺失值數(shù)量是否刪除的標(biāo)準(zhǔn),比如 thresh=3敬矩,會(huì)在一行/列中至少有 3 個(gè)非空值時(shí)將其保留概行。
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個(gè)以上的行
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 這名字一看就是用來(lái)填充缺失值的业踏。

填充缺失值時(shí),常見的一種方式是使用一個(gè)標(biāo)量來(lái)填充涧卵。例如勤家,這里我樣有缺失的年齡都填充為 0。

fillna()

# 對(duì)于Series對(duì)象來(lái)說(shuō)的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

除了可以使用標(biāo)量來(lái)填充之外柳恐,還可以使用前一個(gè)或后一個(gè)有效值來(lái)填充讼庇。

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

# 用前一行的該列的值進(jìn)行填充
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è)置參數(shù) method='bfill' 或 method='backfill' 可以使用后一個(gè)有效值來(lái)填充歼跟。

# 用后一行的該列的值進(jìn)行填充
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

對(duì)于DataFrame來(lái)說(shuō),該方法使用與Series一樣骚秦,只是填充的數(shù)據(jù)多了而已

注意:在對(duì)Series進(jìn)行修改或填充時(shí)往毡,默認(rèn)時(shí)不會(huì)對(duì)原數(shù)據(jù)對(duì)象修改的,可以在修改嗤详,填充,刪除的方法的參數(shù)中加上inplace=True办龄,那么這時(shí)就不會(huì)有返回值了,再次打印原數(shù)據(jù)時(shí)英融,就會(huì)發(fā)生改變
實(shí)例:
對(duì)DataFrame對(duì)象中的age列每一項(xiàng)都填充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()

除了通過(guò) fillna 方法來(lái)填充缺失值外境肾,還可以通過(guò) interpolate 方法來(lái)填充。默認(rèn)情況下使用線性差值,可以是設(shè)置 method 參數(shù)來(lái)改變方式冷离。

# 使用線性差值進(jìn)行填充
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 

替換缺失值

大家有沒(méi)有想過(guò)一個(gè)問(wèn)題:到底什么才是缺失值呢瞭空?你可能會(huì)奇怪說(shuō),前面不是已經(jīng)說(shuō)過(guò)了么黑毅,None愿卒、np.nan、NaT 這些都是缺失值。但是我也說(shuō)過(guò)了渣刷,這些在 Pandas 的眼中是缺失值鹦肿,有時(shí)候在我們?nèi)祟惖难壑校承┊惓V滴覀円矔?huì)當(dāng)做缺失值來(lái)處理辅柴。

例如碌嘀,在我們的存儲(chǔ)的用戶信息中股冗,假定我們限定用戶都是青年,出現(xiàn)了年齡為 40 的,我們就可以認(rèn)為這是一個(gè)異常值。再比如第焰,我們都知道性別分為男性(male)和女性(female),在記錄用戶性別的時(shí)候妨马,對(duì)于未知的用戶性別都記為了 “unknown”,很明顯湘纵,我們也可以認(rèn)為“unknown”是缺失值。此外滤淳,有的時(shí)候會(huì)出現(xiàn)空白字符串梧喷,這些也可以認(rèn)為是缺失值。

replace()

對(duì)于上面的這種情況脖咐,我們可以使用 replace 方法來(lái)替換缺失值铺敌。
對(duì)于Series對(duì)象

# 將age列的np.nan數(shù)據(jù)項(xiàng)替換為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

也可以指定一個(gè)映射字典。

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

對(duì)于DataFrame來(lái)說(shuō)屁擅,可以在replace方法中加上參數(shù)inplace=True來(lái)做原地操作:可以對(duì)DataFrame适刀,也可以針對(duì)某一列/行(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

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

# 替換多個(gè)值
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

類似地煤蹭,我們可以將特定字符串進(jìn)行替換.

除了可以替換特定的值之外笔喉,還可以使用正則表達(dá)式來(lái)替換,如:將空白字符串替換成空值硝皂。

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

使用對(duì)象填充

除了我們自己手動(dòng)丟棄常挚、填充已經(jīng)替換缺失值之外,我們還可以使用對(duì)象來(lái)填充稽物。

例如有兩個(gè)關(guān)于用戶年齡的 Series奄毡,其中一個(gè)有缺失值,另一個(gè)沒(méi)有贝或,我們可以將沒(méi)有的缺失值的 Series 中的元素傳給有缺失值的吼过。

對(duì)于Series:

# 數(shù)據(jù)完整的Series對(duì)象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對(duì)象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

對(duì)于DataFrame,與Series一樣。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末咪奖,一起剝皮案震驚了整個(gè)濱河市盗忱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌羊赵,老刑警劉巖趟佃,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡闲昭,警方通過(guò)查閱死者的電腦和手機(jī)罐寨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)序矩,“玉大人鸯绿,你說(shuō)我怎么就攤上這事◆さ恚” “怎么了楞慈?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)啃擦。 經(jīng)常有香客問(wèn)我囊蓝,道長(zhǎng),這世上最難降的妖魔是什么令蛉? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任聚霜,我火速辦了婚禮,結(jié)果婚禮上珠叔,老公的妹妹穿的比我還像新娘蝎宇。我一直安慰自己,他們只是感情好祷安,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布姥芥。 她就那樣靜靜地躺著,像睡著了一般汇鞭。 火紅的嫁衣襯著肌膚如雪凉唐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天霍骄,我揣著相機(jī)與錄音台囱,去河邊找鬼。 笑死读整,一個(gè)胖子當(dāng)著我的面吹牛簿训,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播米间,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼强品,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了屈糊?” 一聲冷哼從身側(cè)響起的榛,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎另玖,沒(méi)想到半個(gè)月后困曙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谦去,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年慷丽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鳄哭。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡要糊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出妆丘,到底是詐尸還是另有隱情锄俄,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布勺拣,位于F島的核電站奶赠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏药有。R本人自食惡果不足惜毅戈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望愤惰。 院中可真熱鬧苇经,春花似錦、人聲如沸宦言。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)奠旺。三九已至蜘澜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間响疚,已是汗流浹背兼都。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留稽寒,地道東北人扮碧。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像杏糙,于是被迫代替她去往敵國(guó)和親慎王。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355