pandas 缺失值、重復值的處理與值的替換


一、刪除缺失值

在進行數據分析和建模的過程中,我們80%的時間往往花在數據准備上:加載、清理、轉換、處理和重新排列。為了提高這一過程的效率,Pandas提供了一系列的高級、靈活和快速的工具集,配合Python語言內置的處理功能,可以滿足絕大多數場景下的使用需求。

Pandas中,使用numpy.nan標識缺失值,在打印的時候,經常以空字符串、NA、NaN、NULL等形式出現。Python內置的None值也被當作缺失值處理。但合法的缺失值只有NaN和None,另外一些我們自己定義的缺失值不屬於語法上的,比如你將-999看作缺失值。

在Pandas中, None和NaN的區別:

  • None被看作一個object對象,需要消耗更多的資源,處理速度更慢。不支持一些數學操作,因為None+數字是錯誤的語法。很多時候None會自動轉換成NaN。
  • NaN是float64類型,雖然名字叫做‘不是一個數’,但卻屬於數字類,可以進行數學運算不會報錯,雖然所有和它進行計算的最終結果依然是NaN。它的運算速度更快,還支持全局性的操作。

以下是主要的缺失值處理方法:

  • dropna:刪除缺失值
  • fillna: 用某些值填充缺失的數據或使用插值方法(比如ffill\bfill)
  • isnull:判斷哪些值是缺失值,返回布爾
  • notnull:isnull的反函數

通常使用dropna方法濾刪除缺失值,默認它不直接修改數據,而是返回一個新對象。如果想原地修改,舉一反三,請嘗試inplace參數:

In [12]: from numpy import nan as NA  # 導入慣例
In [13]: s = pd.Series([1, NA, 3.5, NA, 7]) In [14]: s Out[14]: 0 1.0
1 NaN 2    3.5
3 NaN 4    7.0 dtype: float64 In [15]: s.dropna()  # 本質上就是把缺失值刪除
Out[15]: 0 1.0
2    3.5
4    7.0 dtype: float64 In [16]: s[s.notnull()]  # 等同於上面的操作
Out[16]: 0 1.0
2    3.5
4    7.0 dtype: float64

在處理DataFrame對象的缺失值的時候,可能會復雜點。無法刪除df的單個元素,只能整行整列的刪除,dropna默認情況下會刪除包含缺失值的行!為什么呢?因為DataFrame對象的每一行數據,在實際中,相當於一個樣本,大量的樣本中刪除了一條,關系不大。但DataFrame對象的每一列相當於大量樣本中共同的某個特征的值,如果刪除了一個特征,那么對整個樣本集的影響非常大。

In [20]: df = pd.DataFrame([[1, 6.5, 3],[1, NA, NA],[NA, NA, NA],[NA, 6.5,3]]) In [21]: df Out[21]: 0 1    2 0 1.0  6.5  3.0
1  1.0 NaN NaN 2 NaN NaN NaN 3  NaN  6.5  3.0 In [22]: df.dropna() # 只剩1行了
Out[22]: 0 1    2 0 1.0  6.5  3.0 In [23]: df.dropna(how='all') # 只將整行都是缺失值的刪除
Out[23]: 0 1    2 0 1.0  6.5  3.0
1  1.0 NaN NaN 3  NaN  6.5  3.0 In [24]: df[4] = NA  # 新增一列全是缺失值
In [25]: df Out[25]: 0 1    2   4 0 1.0  6.5  3.0 NaN 1  1.0 NaN NaN NaN 2 NaN NaN NaN NaN 3  NaN  6.5  3.0 NaN In [26]: df.dropna(axis=1, how='all') # 指定以列的形式刪除
Out[26]: 0 1    2 0 1.0  6.5  3.0
1  1.0 NaN NaN 2 NaN NaN NaN 3  NaN  6.5  3.0

注意上面axis和how參數的用法。

還可以通過thresh參數設置行或列中非缺失值的最小數量,在此數量以下的將被刪除。

二、補全缺失值

所有數據都是寶貴的,大多數時候,我們不希望丟棄原始數據,而是補全缺失值。

fillna是補全缺失值的方法,為它提供一個固定值即可:

In [31]: df = pd.DataFrame(np.random.randn(7,3)) In [32]: df Out[32]: 0 1         2 0 -0.229682 -0.483246 -0.063835
1  0.716649  1.593639 -1.364550
2 -1.362614  1.628310 -1.617992
3  1.128828 -1.120265 -0.657313
4  1.078143  1.136835 -0.427125
5  0.441696  0.219477  0.695700
6 -0.501183  1.453678 -2.734985 In [33]: df.iloc[:4, 1] = NA In [35]: df.iloc[:2, 2] = NA In [36]: df Out[36]: 0 1         2 0 -0.229682 NaN NaN 1  0.716649 NaN NaN 2 -1.362614       NaN -1.617992
3  1.128828       NaN -0.657313
4  1.078143  1.136835 -0.427125
5  0.441696  0.219477  0.695700
6 -0.501183  1.453678 -2.734985 In [37]: df.fillna(0) Out[37]: 0 1         2 0 -0.229682  0.000000  0.000000
1  0.716649  0.000000  0.000000
2 -1.362614  0.000000 -1.617992
3  1.128828  0.000000 -0.657313
4  1.078143  1.136835 -0.427125
5  0.441696  0.219477  0.695700
6 -0.501183  1.453678 -2.734985

也可以提供一個字典,為不同的列設定不同的填充值。

In [38]: df.fillna({1:1, 2:2}) Out[38]: 0 1         2 0 -0.229682  1.000000  2.000000
1  0.716649  1.000000  2.000000
2 -1.362614  1.000000 -1.617992
3  1.128828  1.000000 -0.657313
4  1.078143  1.136835 -0.427125
5  0.441696  0.219477  0.695700
6 -0.501183  1.453678 -2.734985

當然,fillna也不會原地修改數據,如果你想,請使用inplace參數:

In [39]: _ = df.fillna(0, inplace=True) In [40]: df Out[40]: 0 1         2 0 -0.229682  0.000000  0.000000
1  0.716649  0.000000  0.000000
2 -1.362614  0.000000 -1.617992
3  1.128828  0.000000 -0.657313
4  1.078143  1.136835 -0.427125
5  0.441696  0.219477  0.695700
6 -0.501183  1.453678 -2.734985

也可以使用ffill和bfill這種插值法填充缺失值:

In [41]: df = pd.DataFrame(np.random.randn(6,3)) In [42]: df.iloc[2:, 1]=NA In [43]: df.iloc[4:, 2]=NA In [44]: df Out[44]: 0 1         2 0 -0.858762  0.083342 -0.315598
1 -0.211846  0.076648  1.188298
2 -0.513364       NaN  0.079216
3  0.398399       NaN -0.290225
4 -1.375898 NaN NaN 5  0.932812 NaN NaN In [45]: df.fillna(method='ffill') # 使用前一個值進行填充
Out[45]: 0 1         2 0 -0.858762  0.083342 -0.315598
1 -0.211846  0.076648  1.188298
2 -0.513364  0.076648  0.079216
3  0.398399  0.076648 -0.290225
4 -1.375898  0.076648 -0.290225
5  0.932812  0.076648 -0.290225 In [46]: df.fillna(method='ffill',limit=2)  # 限制填充次數
Out[46]: 0 1         2 0 -0.858762  0.083342 -0.315598
1 -0.211846  0.076648  1.188298
2 -0.513364  0.076648  0.079216
3  0.398399  0.076648 -0.290225
4 -1.375898       NaN -0.290225
5  0.932812       NaN -0.290225 In [47]: df.fillna(method='bfill')  # 后向填充此時無效
Out[47]: 0 1         2 0 -0.858762  0.083342 -0.315598
1 -0.211846  0.076648  1.188298
2 -0.513364       NaN  0.079216
3  0.398399       NaN -0.290225
4 -1.375898 NaN NaN 5  0.932812       NaN       NaN

其實使用fillna有很多技巧,需要大家平時多收集多嘗試,比如使用平均值來填充:

In [48]: s = pd.Series([1, NA, 3.5, NA, 7]) In [49]: s.fillna(s.mean()) Out[49]: 0 1.000000
1    3.833333
2    3.500000
3    3.833333
4    7.000000 dtype: float64

三、刪除重復值

原始數據中,往往包含大量重復的行,需要我們刪除,讓數據集更健康。

In [51]: df = pd.DataFrame({'k1':['one','two']*3 + ['two'], 'k2':[1,1,2,3,3,4,4]}) In [52]: df  # 最后一行是重復的
Out[52]: k1 k2 0 one 1
1  two   1
2  one   2
3  two   3
4  one   3
5  two   4
6  two   4 In [53]: df.duplicated()  # 
Out[53]: 0 False 1 False 2 False 3 False 4 False 5 False 6 True dtype: bool In [54]: df.drop_duplicates() Out[54]: k1 k2 0 one 1
1  two   1
2  one   2
3  two   3
4  one   3
5  two   4 In [55]: df # 並沒有改變原數據
Out[55]: k1 k2 0 one 1
1  two   1
2  one   2
3  two   3
4  one   3
5  two   4
6  two   4

上面,使用duplicated方法判斷各行是否有重復,並返回一個布爾值Series。然后使用drop_duplicates方法將重復行刪除,留下那些不重復的。

如果想指定根據某列的數據進行去重判斷和操作,可以指定列名:

In [56]: df['v1'] = range(7) In [57]: df Out[57]: k1 k2 v1 0 one 1 0 1  two   1   1
2  one   2   2
3  two   3   3
4  one   3   4
5  two   4   5
6  two   4   6 In [58]: df.drop_duplicates(['k1']) Out[58]: k1 k2 v1 0 one 1 0 1  two   1   1

默認情況下都是保留第一個觀察到的值,如果想保留最后一個,可以使用參數keep='last':

In [59]: df.drop_duplicates(['k1','k2'], keep='last') Out[59]: k1 k2 v1 0 one 1 0 1  two   1   1
2  one   2   2
3  two   3   3
4  one   3   4
6  two   4   6

四、替換值

可以使用replace將pandas對象中的指定值替換為別的值:

In [77]: df = pd.DataFrame(np.random.randint(12,size=(4,3))) In [78]: df Out[78]: 0 1   2 0 4  5  10
1  3  0   3
2  7  7   4
3  6  4   4 In [79]: df.replace(4, NA)  # 將4替換為缺失值
Out[79]: 0 1     2 0 NaN 5.0  10.0
1  3.0  0.0   3.0
2  7.0  7.0 NaN 3  6.0 NaN NaN In [80]: df.replace([3,4], NA) # 將3和4都替換為缺失值
Out[80]: 0 1     2 0 NaN 5.0  10.0
1  NaN  0.0 NaN 2  7.0  7.0 NaN 3  6.0 NaN NaN In [81]: df.replace([3,4], [NA,0]) # 3和4分別替換為缺失值和0
Out[81]: 0 1     2 0 0.0  5.0  10.0
1  NaN  0.0 NaN 2  7.0  7.0   0.0
3  6.0  0.0   0.0 In [82]: df.replace({3:NA,4:0})  # 參數的字典形式
Out[82]: 0 1     2 0 0.0  5.0  10.0
1  NaN  0.0 NaN 2  7.0  7.0   0.0
3  6.0  0.0   0.0


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM