Pandas SettingwithCopyWarning 警告處理
數據處理時,常使用 python 的數據結構及分析工具 Pandas (Python Data Analysis Library) ,在使用時經常遇到一項警告: SettingWithCopyWarning ,這警告是學習 Pandas 時最常見的障礙之一,從 Stack Overflow 的討論串數量就知道自己並不孤單。來回爬了幾次,還是有看沒懂,確認過執行結果如預期,就先把警告忽略。
直到發現這篇 SettingwithCopyWarning- How to Fix This Warning in Pandas,有著清楚定義 + 圖片支援 + 這警告的歷史,耐心讀完後終於瞭解如何避免,在使用 Pandas 時有相當大的幫助,可避免預期外的數據操作,導致結果錯誤,以下摘錄重點。
這是個警告,而非錯誤,所以程式碼還是會執行。它通知你的操作可能未達到預期的效果,因此應檢查結果以確保沒有犯錯。做決定前,最好花點時間了解發生什麼事情。
首先,瞭解 pandas 中,你的操作,有可能返回 (return) 的是數據的 view 或是 copy。
數據操作定義:
這情況就照著警告內容,使用 loc,讓 pandas 知道要 set 原始 DataFrame 。
但有時明明已經用了還是跳出警告,可能是你用了 Chained assignment 而沒察覺 (Hidden chaining)
又會跳出警告來!但檢查一下,數據如你所想寫入了
問題出在
在這情況,修改
解決方法:加上
好消息是,這問題很容易解決,清楚地告訴 pandas 你要的是 copy 還是創造一個新的 dataframe
如果要更改原稿,請單獨使用 set; 如果要複製,請確保強迫 pandas 這樣做, 這會省下找 bug 的時間。
另外,即使僅在 set 時才會發生 SettingWithCopyWarning ,但最好還是避免以 Chained assignment 進行 get。 鍊式操作較慢,如果以後決定添加 set 操作,則會導致問題。
原文後面還有更多細節說明,有興趣可以研究一下。
直到發現這篇 SettingwithCopyWarning- How to Fix This Warning in Pandas,有著清楚定義 + 圖片支援 + 這警告的歷史,耐心讀完後終於瞭解如何避免,在使用 Pandas 時有相當大的幫助,可避免預期外的數據操作,導致結果錯誤,以下摘錄重點。
這警告在說什麼?
這是個警告,而非錯誤,所以程式碼還是會執行。它通知你的操作可能未達到預期的效果,因此應檢查結果以確保沒有犯錯。做決定前,最好花點時間了解發生什麼事情。
首先,瞭解 pandas 中,你的操作,有可能返回 (return) 的是數據的 view 或是 copy。
當你試著更改資料時,可能會導致問題:
你可能想修改原始 df1 數據(左),或是只想修改 df2(右邊)。這警告叫你開一下這薛丁格的盒子,確認裡面貓的生死。
from here |
你可能想修改原始 df1 數據(左),或是只想修改 df2(右邊)。這警告叫你開一下這薛丁格的盒子,確認裡面貓的生死。
警告原因:Chained assignment 及 Hidden chaining
數據操作定義:
- 分配 (Assignment,or set) — 設置某些值的操作;如
data = pd.read_csv('xbox-3-day-auctions.csv')
- 取得 (Access, or get) — 返回某物值的操作;如下面的索引和鏈接
- 索引 (Indexing) — 對數據子集的分配或取得方法; 如
data [1:5]
- 鏈接 (Chaining) — 連續使用多個索引操作; 如
data [1:5] [1:3]
Chained assignmen = 4 + 1
data[data.bidder == 'parakeet2004']['bidderrate'] = 100
這時就會跳出警告
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ipykernel/__main__.py:1: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.Try using .loc[row_indexer,col_indexer] = value insteadSee the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy if __name__ == '__main__':
這情況就照著警告內容,使用 loc,讓 pandas 知道要 set 原始 DataFrame 。
但有時明明已經用了還是跳出警告,可能是你用了 Chained assignment 而沒察覺 (Hidden chaining)
winners = data.loc[data.bid == data.price] mean_win_time = winners.bidtime.mean() ... # 20 lines of code mode_open_bid = winners.openbid.mode() winners.loc[304, 'bidder'] = 'therealname' # 原本無值,在這想設定為'therealname'
又會跳出警告來!但檢查一下,數據如你所想寫入了
print(winners.loc[304, 'bidder']) therealname
問題出在
winners
,pandas 不確定是原 DataFrame
的copy 還是 view, 所以對 winners
進行索引時(就算用了 loc
),實際上是 chained indexing。在這情況,修改
winners
時,可能也修改了 data
。
解決方法:加上.copy()
好消息是,這問題很容易解決,清楚地告訴 pandas 你要的是 copy 還是創造一個新的 dataframe
winners = data.loc[data.bid == data.price].copy() winners.loc[304, 'bidder'] = 'therealname' print(winners.loc[304, 'bidder']) print(data.loc[304, 'bidder'])
therealname nan
訣竅是學會識別 Chained assignmen ,並不惜一切代價避免。
如果要更改原稿,請單獨使用 set; 如果要複製,請確保強迫 pandas 這樣做, 這會省下找 bug 的時間。
另外,即使僅在 set 時才會發生 SettingWithCopyWarning ,但最好還是避免以 Chained assignment 進行 get。 鍊式操作較慢,如果以後決定添加 set 操作,則會導致問題。
原文後面還有更多細節說明,有興趣可以研究一下。
其實若 loc 使用正確的話也不會跳警告,安全的寫法為:
回覆刪除mask = (data.bidder == 'parakeet2004')
data.loc[mask, 'bidderrate'] = 100
抱歉過了許久才發現留言,謝謝你的分享😁
刪除