[Python3] Pandas v1.0 —— (二) 處理缺失值


[ Pandas version: 1.0.1 ]


四、處理缺失值

(一)選擇處理缺失值的方法

在數據表或 DataFrame 中有很多識別缺失值的方法。一般情況下可以分爲兩種:

  • 一種方法是通過一個覆蓋全局的掩碼表示缺失值
  • 另一種方法是用一個標籤值表示缺失值

(二)Pandas的缺失值

Pandas用標籤方法表示缺失值,包括兩種Python原有的缺失值:浮點數據類型的 NaN 值,以及Python的 None 對象。

1. None: Python對象類型的缺失值

Pandas可以使用的第一種缺失值標籤是 None,它是Python單體對象,經常在代碼中表示缺失值。

由於 None 是一個Python對象,所以不能作爲任何 NumPy/Pandas 數組類型的缺失值,只能用於’object’數組類型(由Python對象構成的數組)

import numpy as np
import pandas as pd

vals1 = np.array([1, None, 3, 4])
vals1 			#輸出:array([1, None, 3, 4], dtype=object)

# dtype=object表示NumPy認爲這個數組是Python對象構成的。
# 雖然這種類型在某些情景中很有用,對數據的任何操作最終都會在Python層面完成。
# 但是在進行常見的快速操作時,這種類型比其他與原生類型數組要消耗更多的資源。

使用Python對象構成的數組意味着如果對一個包含 None 的數組進行累計操作(如sum(), min())會出現類型錯誤 TypeError

因此,在Python中沒有定義整數與 None 之間的運算。

2. NaN: 數值類型的缺失值

另一種缺失值的標籤是 NaN(全稱 Not a Number,不是一個數字),是一種按照IEEE浮點數標準設計、在任何系統中都兼容的特殊浮點數。

vals2 = np.array([1, np.nan, 3, 4])
vals2 			#輸出:array([ 1., nan,  3.,  4.])
vals2.dtype 	#輸出:dtype('float64')

# Numpy會爲這個數組選擇一個原生浮點類型,意味着這個數組會被編譯成C代碼從而實現快速操作

NaN 會將與它接觸過的數據同化,無論和 NaN 進行何種操作,最終結果都是NaN。

1 + np.nan 		#輸出:nan
0 * np.nan 		#輸出:nan

# 雖然這些累計操作的結果定義時合理的(無異常),但是並非總是有效的:
vals2.sum(), vals2.min(), vals2.max() 	#輸出:(nan, nan, nan)

Numpy提供一些特殊的累計函數,可以忽略缺失值的影響:

np.nansum(vals2), np.nanmin(vals2), np.nanmax(vals2) 	#輸出:(8.0, 1.0, 4.0)

NaN 是一種特殊的浮點數,不是整數、字符串以及其他數據類型。

3. Pandas中 NaN 與 None 的差異

Pandas把 NaN 和 None 看成是可以等價交換的,在適當的時候會將兩者進行替換:Pandas會將沒有標籤值的數據類型自動轉換爲 NA 。

除了將整型數組的缺失值強制轉換爲浮點數,Pandas還會自動將 None 轉換爲 NaN。

pd.Series([1, np.nan, 2, None])
# 0    1.0
# 1    NaN
# 2    2.0
# 3    NaN
# dtype: float64

x = pd.Series(range(2), dtype=int)
# 0    0
# 1    1
# dtype: int64

x[0] = None
# 0    NaN
# 1    1.0
# dtype: float64

Pandas對不同類型缺失值的強制轉換規則

類型 				缺失值轉換規則			NA標籤值
floating 浮點型		無變化					np.nan
object 對象類型		無變化					None 或 np.nan
integer 整數類型		強制轉換爲 float64		np.nan
boolean 布爾類型		強制轉換爲 object 		None 或 np.nan

# 注:Pandas中字符串類型的數據通常是用object類型存儲

(三)處理缺失值

Pandas提供了一些方法來發現、剔除、替換數據結構中的缺失值

isnull() 	# 創建一個布爾類型的掩碼標籤缺失值
notnull()	# 與isnull()操作相反
dropna() 	# 返回一個剔除缺失值的數據
fillna() 	# 返回一個填充了缺失值的數據副本

1. 發現缺失值

Pandas數據結構有兩種方法可以發現缺失值:isnull()notnull(),每種方法都返回布爾類型的掩碼數據。

data = pd.Series([1, np.nan, 'hello', None])
data
# 0        1
# 1      NaN
# 2    hello
# 3     None
# dtype: object

data.isnull()
# 0    False
# 1     True
# 2    False
# 3     True
# dtype: bool

# 布爾類型掩碼數組可以直接作爲Series或DataFrame索引使用
data[data.notnull()]
# 0        1
# 2    hello
# dtype: object

2. 剔除缺失值

除了前面的掩碼方法,還有兩種缺失值處理方法:dropna()(剔除缺失值)和fillna()(填充缺失值)

data.dropna()
# 0        1
# 2    hello
# dtype: object

對於DataFrame的參數設置:

默認情況下,dropna()會剔除任何包含缺失值的整行數據。

DataFrame中可以設置按不同座標軸剔除缺失值,如axis=1axis='columns'會剔除任何包含缺失值的整列數據。

有時候只需要剔除全部或絕大多數時缺失值的行或列,可以通過設置how或thresh參數來滿足(設置剔除行或列缺失值的數量閾值)

  • 默認設置how='any'(只要有缺失值就剔除整行或整列)
  • 可以設置how='all'(只剔除全部是缺失值的行或列)
  • 通過thresh參數設置行或列中非缺失值的最小數量
df = pd.DataFrame([[1, np.nan, 2], [2, 3, 5], [np.nan, 4, 6]])
df
#      0    1  2
# 0  1.0  NaN  2
# 1  2.0  3.0  5
# 2  NaN  4.0  6

df.dropna()
#      0    1  2
# 1  2.0  3.0  5

df.dropna(axis='columns')
#    2
# 0  2
# 1  5
# 2  6

df[3] = np.nan
df
#      0    1  2   3
# 0  1.0  NaN  2 NaN
# 1  2.0  3.0  5 NaN
# 2  NaN  4.0  6 NaN

df.dropna(axis='columns', how='all')
#      0    1  2
# 0  1.0  NaN  2
# 1  2.0  3.0  5
# 2  NaN  4.0  6

df.dropna(axis='rows', thresh=3) 	#每行至少3個非缺
#      0    1  2   3
# 1  2.0  3.0  5 NaN

3. 填充缺失值

有時需要把缺失值替換成有效的數值。有效數值包括單獨數值,經過填充或轉換得到的值。

可以通過isnull()方法建立掩碼來填充缺失值,Pandas也提供了fillna()方法(返回填充了缺失值後的數組副本)

fillna()方法:

  • 可以用單獨數值填充
  • 可以用缺失值前面的有效值來從前往後填充(forward-fill):fillna(method='ffill')
  • 可以用缺失值後面的有效值來從後往前填充(back-fill):fillna(method='bfill')
  • DataFrame操作時可以設置座標軸參數
  • 注意:如果從前往後填充時,需要填充的缺失值前面沒有值,那麼它仍然是缺失值
data = pd.Series([1, np.nan, 2, None, 3], index=list('abcde'))
data
# a    1.0
# b    NaN
# c    2.0
# d    NaN
# e    3.0
# dtype: float64

# 單獨數值填充
data.fillna(0)
# a    1.0
# b    0.0
# c    2.0
# d    0.0
# e    3.0
# dtype: float64

# 從前往後填充
data.fillna(method='ffill')
# a    1.0
# b    1.0
# c    2.0
# d    2.0
# e    3.0
# dtype: float64

# 從後往前填充
data.fillna(method='bfill')
# a    1.0
# b    2.0
# c    2.0
# d    3.0
# e    3.0
# dtype: float64

# DataFrame按座標軸填充
df
#      0    1  2   3
# 0  1.0  NaN  2 NaN
# 1  2.0  3.0  5 NaN
# 2  NaN  4.0  6 NaN

df.fillna(method='ffill', axis=1)
#      0    1    2    3
# 0  1.0  1.0  2.0  2.0
# 1  2.0  3.0  5.0  5.0
# 2  NaN  4.0  6.0  6.0

Pandas 相關閱讀:

[Python3] Pandas v1.0 —— (一) 對象、數據取值與運算
[Python3] Pandas v1.0 —— (二) 處理缺失值 【本文】
[Python3] Pandas v1.0 —— (三) 層級索引
[Python3] Pandas v1.0 —— (四) 合併數據集
[Python3] Pandas v1.0 —— (五) 累計與分組
[Python3] Pandas v1.0 —— (六) 數據透視表
[Python3] Pandas v1.0 —— (七) 向量化字符串操作
[Python3] Pandas v1.0 —— (八) 處理時間序列
[Python3] Pandas v1.0 —— (九) 高性能Pandas: eval()與query()


總結自《Python數據科學手冊》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章