IT Learning

実践形式でITのお勉強

Python

【Python】SettingWithCopyWarnig: A value is trying to be set on a copy of a slice from DataFrame が出た時の対処法

投稿日:

概要

PythonのPandasでDataFrameを操作していた際に、以下のエラーに遭遇したのでその対処ほうについてメモします。

SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.

環境

  • Python 3.8.10
  • pandas 1.3.5

発生状況

まず次のようなDataFrameを作成します。

import pandas as pd
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9,]], columns=['col1', 'col2', 'col3'])
df.head()

上記で作成したDataFrameから特定のカラムなどで抽出したものを変数へ格納し、さらにその変数(DataFrame)に列を追加しようとしたところSettingWithCopyWarnigが発生しました。

df_tmp = df
df_tmp['col4'] = df['col1']
df_tmp = df[['col1','col2']]
df_tmp['col5'] = df['col2']
----
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

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  df_tmp['col4'] = df['col1']

Warningは、「値がデータフレームのスライスのコピーが代入されようとしている。代わりに.locメソッドを試してください」といった内容でした。

Warningの解釈

途中にdisplay(df)を挟んでdfの挙動を確認してみたところ以下の通りでした。

df_tmp = df
df_tmp['col4'] = df['col1']
display(df) # ...(1)
df_tmp = df[['col1','col2']]
display(df) # ...(2)
df_tmp['col5'] = df['col2'] 
display(df) # ...(3)

(1), (2), (3)の結果はいずれも以下の通りでした。

この挙動から以下のように解釈しました。

df_tmp = df
df_tmp['col4'] = df['col1'] #参照渡しになっている
df_tmp = df[['col1','col2']] #df_tmpへコピーが渡されている(dfの値は変わらない)
df_tmp['col5'] = df['col2'] #コピーに対する代入なのでSettingWithCopyWarningが出る

どうやら、dfをそのまま = で渡した時には参照渡しになるが、列指定でスライスして渡した場合にはコピーが渡されるようです。

そして、コピー先のデータフレームに対して元のデータフレームのスライスを代入しようとした場合にPythonが気を利かせてWarningしている様子でした。

対処法

次のようにコピーで渡す箇所については明示的に.copy()メソッドを使用すると SettingWithCopyWarnig は出なくなりました。

df_tmp = df
df_tmp['col4'] = df['col1']
df_tmp = df[['col1','col2']].copy()
df_tmp['col5'] = df['col2']

まとめ

データフレームは参照渡しかコピー渡しかが分かりにくいためS SettingWithCopyWarnig が出た場合はなるべく明示的にcopy()を使用してやるのが良いかもしれません。

Related

-Python

執筆者:


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です