Pandas切片操作:很容易忽視的SettingWithCopyWarning


Pandas是一個強大的分析結構化數據的工具集,主要用於數據挖掘和數據分析,同時也提供數據清洗功能。

很多初學者在數據的選取,修改和切片時經常面臨一些困惑。這是因為Pandas提供了太多方法可以做同樣的事情,方法選擇不當,可能導致一些意想不到的錯誤。

Pandas切片

Pandas數據訪問方式包括:df[] ,.at,.iat,.loc,.iloc(之前有ix方法,pandas1.0之后已被移除)

  • df[] :直接索引
  • at/iat:通過標簽或行號獲取某個數值的具體位置。
  • loc:通過標簽選取數據,即通過index和columns的值進行選取。loc方法有兩個參數,按順序控制行列選取,范圍包括start和end。
  • iloc:通過行號選取數據,即通過數據所在的自然行列數為選取數據。iloc方法也有兩個參數,按順序控制行列選取。

它們之間的區別不是文本重點,大家可以新建一個dataframe練習一下,本文我們主要來一個錯誤示范,然后給大家提一些合理的建議。

錯誤示范

新建一個DataFrame

df = pd.DataFrame(
{'x':[1,5,4,3,4,5],
'y':[.1,.5,.4,.3,.4,.5],
'w':[11,15,14,13,14,15]})

   x    y   w
0  1  0.1  11
1  5  0.5  15
2  4  0.4  14
3  3  0.3  13
4  4  0.4  14
5  5  0.5  15

假設我們要查找與“x”列對應的所有DataFrame元素都大於3,並根據此更改將所有對應的“ y”值更改為50。
我們來先試一個看起來毫無問題的方法

df[df['x']>3]['y']=50
運行之后,df沒有任何變化,Warning如下:

A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

根據提示信息,我們使用loc方法

df.loc[df['x']>3,'y']=50
   x     y   w
0  1   0.1  11
1  5  50.0  15
2  4  50.0  14
3  3   0.3  13
4  4  50.0  14
5  5  50.0  15

得到預期結果√
這是為什么呢?這里我們就遇到了所謂的“鏈接索引”,具體原因是使用了兩個索引器,例如: df[][]
df[df['x']>3] 導致Pandas創建原始DataFrame的單獨副本
df[df['x']>3]['y'] = 50 將新值分配給“ y”列,但在此臨時創建的副本上,而不是原始DataFrame上。

反轉切片的順序時,即先調用列,然后再調用我們要滿足的條件,便得到了預期的結果:

df['y'][df['x']>3]=50

   x     y   w
0  1   0.1  11
1  5  50.0  15
2  4  50.0  14
3  3   0.3  13
4  4  50.0  14
5  5  50.0  15

但是同樣會給出一個Warning:
A value is trying to be set on a copy of a slice from a DataFrame

SettingWithCopyWarning 是一個警告 Warning,而不是錯誤 Error。
這是因為,當我們從DataFrame中僅選擇一列時,Pandas會創建一個視圖,而不是副本。關於視圖和副本的區別,下圖最為形象:

df[]方法會創建視圖

df 
   x    y   w
0  1  0.1  11
1  5  0.5  15
2  4  0.4  14
3  3  0.3  13
4  4  0.4  14
5  5  0.5  15

z = df['y'] # view of column 'y'
z[z>=0.5] = 30

z
0     0.1
1    30.0
2     0.4
3     0.3
4     0.4
5    30.0

df
   x     y   w
0  1   0.1  11
1  5  30.0  15
2  4   0.4  14
3  3   0.3  13
4  4   0.4  14
5  5  30.0  15

當我們創建了視圖后,pandas就會出現warning,因為它不知道我們是否只想更改y系列(通過z)或原始值df。
如果我們要提取“z”作為獨立對象怎么辦?pandas提供了copy()方法,當我們將命令更新為以下所示的命令時:

z = df['y'].copy()

我們將在內存中創建一個具有其自己地址的全新對象,並且對“z”進行的任何更新df都將不受影響。
實際上有兩個要點,可以使我們在使用切片和數據操作時免受任何有害影響:

  • 避免鏈接索引。始終選擇.loc/ .iloc(或.at/ .iat)方法;
  • 使用copy() 創建獨立的對象,並保護原始資源免遭不當操縱。

參考

https://www.jianshu.com/p/199a653e9668
https://www.kdnuggets.com/2020/04/stop-hurting-pandas.html


免責聲明!

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



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