程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

pandas 缺失數據處理大全

編輯:Python

作者 | 東哥起飛

來源 | 東哥起飛

利用閒暇之余將有關數據清洗、數據分析的一些技能再次進行分類,裡面也包含了我平時用到的一些小技巧,此次就從數據清洗缺失值處理走起~

所有數據和代碼可在我的GitHub獲取:

https://github.com/xiaoyusmd/PythonDataScience

一、缺失值類型

pandas中,缺失數據顯示為NaN。缺失值有3種表示方法,np.nannonepd.NA

1、np.nan

缺失值有個特點(坑),它不等於任何值,連自己都不相等。如果用nan和任何其它值比較都會返回nan

np.nan == np.nan
>> False

也正由於這個特點,在數據集讀入以後,不論列是什麼類型的數據,默認的缺失值全為np.nan

因為nanNumpy中的類型是浮點,因此整型列會轉為浮點;而字符型由於無法轉化為浮點型,只能歸並為object類型('O'),原來是浮點型的則類型不變。

type(np.nan)
>> float
pd.Series([1,2,3]).dtype
>> dtype('int64')
pd.Series([1,np.nan,3]).dtype
>> dtype('float64')

初學者做數據處理遇見object類型會發懵,不知道這是個啥,明明是字符型,導入後就變了,其實是因為缺失值導致的。

除此之外,還要介紹一種針對時間序列的缺失值,它是單獨存在的,用NaT表示,是pandas的內置類型,可以視為時間序列版的np.nan,也是與自己不相等。

s_time = pd.Series([pd.Timestamp('20220101')]*3)
s_time
>> 0 2022-01-01
   1 2022-01-01
   2 2022-01-01
   dtype:datetime64[ns]
-----------------
s_time[2] = pd.NaT
s_time
>> 0 2022-01-01
   1 2022-01-01
   2 NaT
   dtype:datetime64[ns]

2、None

還有一種就是None,它要比nan好那麼一點,因為它至少自己與自己相等。

None == None
>> True

在傳入數值類型後,會自動變為np.nan

type(pd.Series([1,None])[1])
>> numpy.float64

只有當傳入object類型時是不變的,因此可以認為如果不是人工命名為None的話,它基本不會自動出現在pandas中,所以None大家基本也看不到。

type(pd.Series([1,None],dtype='O')[1])
>> NoneType

3、NA標量

pandas1.0以後的版本中引入了一個專門表示缺失值的標量pd.NA,它代表空整數、空布爾值、空字符,這個功能目前處於實驗階段。

開發者也注意到了這點,對於不同數據類型采取不同的缺失值表示會很亂。pd.NA就是為了統一而存在的。pd.NA的目標是提供一個缺失值指示器,可以在各種數據類型中一致使用(而不是np.nan、None或者NaT分情況使用)。

s_new = pd.Series([1, 2], dtype="Int64")
s_new
>> 0   1
   1   2
   dtype: Int64
-----------------
s_new[1] = pd.NaT
s_new
>> 0    1
   1  <NA>
   dtype: Int64

同理,對於布爾型、字符型一樣不會改變原有數據類型,這樣就解決了原來動不動就變成object類型的麻煩了。

下面是pd.NA的一些常用算術運算和比較運算的示例:

##### 算術運算
# 加法
pd.NA + 1
>> <NA>
-----------
# 乘法
"a" * pd.NA
>> <NA>
-----------
# 以下兩種其中結果為1
pd.NA ** 0
>> 1
-----------
1 ** pd.NA
>> 1
##### 比較運算
pd.NA == pd.NA
>> <NA>
-----------
pd.NA < 2.5
>> <NA>
-----------
np.log(pd.NA)
>> <NA>
-----------
np.add(pd.NA, 1)
>> <NA>

二、缺失值判斷

了解了缺失值的幾種形式後,我們要知道如何判斷缺失值。對於一個dataframe而言,判斷缺失的主要方法就是isnull()或者isna(),這兩個方法會直接返回TrueFalse的布爾值。可以是對整個dataframe或者某個列。

df = pd.DataFrame({
      'A':['a1','a1','a2','a3'],
      'B':['b1',None,'b2','b3'],
      'C':[1,2,3,4],
      'D':[5,None,9,10]})
# 將無窮設置為缺失值      
pd.options.mode.use_inf_as_na = True

1、對整個dataframe判斷缺失

df.isnull()
>> A B C D
0 False False False False
1 False True False True
2 False False False False
3 False False False False

2、對某個列判斷缺失

df['C'].isnull()
>> 0    False
   1    False
   2    False
   3    False
Name: C, dtype: bool

如果想取非缺失可以用notna(),使用方法是一樣的,結果相反。

三、缺失值統計

1、列缺失

一般我們會對一個dataframe進行缺失統計,查看每個列有多少缺失,如果缺失率過高再進行刪除或者插值等操作。那麼直接在上面的isnull()返回的結果上直接應用.sum()即可,axis默認等於0,0是列,1是行。

## 列缺失統計
isnull().sum(axis=0)

2、行缺失

但是很多情況下,我們也需要對進行缺失值判斷。比如一行數據可能一個值都沒有,如果這個樣本進入模型,會造成很大的干擾。因此,行列兩個缺失率通常都要查看並統計。

操作很簡單,只需要在sum()中設置axis=1即可。

## 行缺失統計
isnull().sum(axis=1)

3、缺失率

有時我不僅想要知道缺失的數量,我更想知道缺失的比例,即缺失率。正常可能會想到用上面求得數值再比上總行數。但其實這裡有個小技巧可以一步就實現。

## 缺失率
df.isnull().sum(axis=0)/df.shape[0]
## 缺失率(一步到位)
isnull().mean()

四、缺失值篩選

篩選需要loc配合完成,對於行和列的缺失篩選如下:

# 篩選有缺失值的行
df.loc[df.isnull().any(1)]
>> A B C D
1 a1 None 2 NaN
-----------------
# 篩選有缺失值的列
df.loc[:,df.isnull().any()]
>> B D
0 b1 5.0
1 None NaN
2 b2 9.0
3 b3 10.0

如果要查詢沒有缺失值的行和列,可以對表達式用取反~操作:

df.loc[~(df.isnull().any(1))]
>> A B C D
0 a1 b1 1 5.0
2 a2 b2 3 9.0
3 a3 b3 4 10.0

上面使用了any判斷只要有缺失就進行篩選,也可以用all判斷是否全部缺失,同樣可以對行裡進行判斷,如果整列或者整行都是缺失值,那麼這個變量或者樣本就失去了分析的意義,可以考慮刪除。

五、缺失值填充

一般我們對缺失值有兩種處理方法,一種是直接刪除,另外一種是保留並填充。下面先介紹填充的方法fillna

# 將dataframe所有缺失值填充為0
df.fillna(0)
>> A B C D
0 a1 b1 1 5.0
1 a1 0 2 0.0
2 a2 b2 3 9.0
3 a3 b3 4 10.0
--------------
# 將D列缺失值填充為-999
df.D.fillna('-999')
>> 0       5
   1    -999
   2       9
   3      10
Name: D, dtype: object

方法很簡單,但使用時需要注意一些參數。

  • inplace:可以設置fillna(0, inplace=True)來讓填充生效,原dataFrame被填充。

  • methond:可以設置methond方法來實現向前或者向後填充,pad/ffill為向前填充,bfill/backfill為向後填充,比如df.fillna(methond='ffill'),也可以簡寫為df.ffill()

df.ffill()
>> A B C D
0 a1 b1 1 5.0
1 a1 b1 2 5.0
2 a2 b2 3 9.0
3 a3 b3 4 10.0

原缺失值都會按照前一個值來填充(B列1行,D列1行)。

除了用前後值來填充,也可以用整個列的均值來填充,比如對D列的其它非缺失值的平均值8來填充缺失值。

df.D.fillna(df.D.mean())
>> 0     5.0
   1     8.0
   2     9.0
   3    10.0
Name: D, dtype: float64

六、缺失值刪除

刪除缺失值也非情況,比如是全刪除還是刪除比較高缺失率,這個要看自己的容忍程度,真實的數據必然會存在缺失的,這個無法避免。而且缺失在某些情況下也代表了一定的含義,要視情況而定。

1、全部直接刪除

# 全部直接刪除
df.dropna()
>> A B C D
0 a1 b1 1 5.0
2 a2 b2 3 9.0
3 a3 b3 4 10.0

2、行缺失刪除

# 行缺失刪除
df.dropna(axis=0)
>> A B C D
0 a1 b1 1 5.0
2 a2 b2 3 9.0
3 a3 b3 4 10.0

3、列缺失刪除

# 列缺失刪除
df.dropna(axis=1)
>> A C
0 a1 1
1 a1 2
2 a2 3
3 a3 4
-------------
# 刪除指定列范圍內的缺失,因為C列無缺失,所以最後沒有變化
df.dropna(subset=['C'])
>> A B C D
0 a1 b1 1 5.0
1 a1 None 2 NaN
2 a2 b2 3 9.0
3 a3 b3 4 10.0

4、按缺失率刪除

這個可以考慮用篩選的方法來實現,比如要刪除列缺失大於0.1的(即篩選小於0.1的)。

df.loc[:,df.isnull().mean(axis=0) < 0.1]
>> A C
0 a1 1
1 a1 2
2 a2 3
3 a3 4
-------------
# 刪除行缺失大於0.1的
df.loc[df.isnull().mean(axis=1) < 0.1]
>> A B C D
0 a1 b1 1 5.0
2 a2 b2 3 9.0
3 a3 b3 4 10.0

七、缺失值參與計算

如果不對缺失值處理,那麼缺失值會按照什麼邏輯進行計算呢?

下面我們一起看一下各種運算下缺失值的參與邏輯。

1、加法

df
>>A B C D
0 a1 b1 1 5.0
1 a1 None 2 NaN
2 a2 b2 3 9.0
3 a3 b3 4 10.0
---------------
# 對所有列求和
df.sum()
>> A    a1a1a2a3
   C          10
   D          24

可以看到,加法是會忽略缺失值的。

2、累加

# 對D列進行累加
df.D.cumsum()
>> 0     5.0
   1     NaN
   2    14.0
   3    24.0
Name: D, dtype: float64
---------------
df.D.cumsum(skipna=False)
>> 0    5.0
   1    NaN
   2    NaN
   3    NaN
Name: D, dtype: float64

cumsum累加會忽略NA,但值會保留在列中,可以使用skipna=False跳過有缺失值的計算並返回缺失值。

3、計數

# 對列計數
df.count()
>> A    4
   B    3
   C    4
   D    3
dtype: int64

缺失值不進入計數范圍裡。

4、聚合分組

df.groupby('B').sum()
>> C D
B  
b1 1 5.0
b2 3 9.0
b3 4 10.0
---------------
df.groupby('B',dropna=False).sum()
>> C D
B  
b1 1 5.0
b2 3 9.0
b3 4 10.0
NaN 2 0.0

聚合時會默認忽略缺失值,如果要缺失值計入到分組裡,可以設置dropna=False。這個用法和其它比如value_counts是一樣的,有的時候需要看缺失值的數量。

以上就是所有關於缺失值的常用操作了,從理解缺失值的3種表現形式開始,到缺失值判斷、統計、處理、計算等。

往期回顧

NLP 類問題建模方案探索實踐

Python 爬蟲中的常見加密算法!

2D變身3D,來看英偉達的AI“新”魔法!

搞定Python幾個常用的數據結構!

分享
點收藏
點點贊
點在看

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved