概要
タイトルの通りです。
以下の warning を再現させる最小限(のつもり)のコードを記録に残しておいたものです。
/pandas/core/indexing.py:1743: 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 instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
isetter(ilocs[0], value)
長い記事を読みたくないので、サクッと読める分量にまとめました。
ほとんど何も考えなくても理解できる記事を目指しています。
ソースコード
google colaboratory 上で発生させました。
1. まずは準備から
import pandas as pd
numbers = pd.DataFrame({'number': [1, 2 ,3 ,4]})
numbers
number
0 1
1 2
2 3
3 4
2. 原因
これが良くないらしい
つまりこれで再現する
# 行方向にスライス
evens = numbers.loc[numbers['number'] % 2 == 0]
evens
number
1 2
3 4
3. 再現
# はい、発生
evens['str'] = ['2', '4']
/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.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 instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
"""Entry point for launching an IPython kernel.
4. 対策
「2. 原因」のところのコードで、スライス後にcopy()
を使えば解決する
# 行方向にスライス、の後にcopy()を追加。これでOK。
evens = numbers.loc[numbers['number'] % 2 == 0].copy()
evens
number
1 2
3 4
# 上記のように、スライス結果をcopy()したものに対してであれば、
# 行追加してもwarningは出ない
evens['str'] = ['2', '4']
5. 結論
スライスしたらcopy()
しよう。
いつもこのwarning出して、原因思い出せなくて時間食う....(´;ω;`)ぐすっ
関連記事
詳細について知りたい場合はこの記事が詳しいです