質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

3110閲覧

SettingWithCopyWarning: エラーを消したい

km0815.lj

総合スコア12

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2021/11/05 09:01

SettingWithCopyWarning: エラーを消したい。

データフレームから、query()メソッドを使い抽出したデータに変更を加えようとすると
「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」
のエラーが出ました。

いろいろ試したところ、抽出データの結果が1行のとき、上記のエラーになるようです。
何か回避策は無いでしょうか。

※例の場合df1['請求書発行日'] = df1['請求書発行日'].fillna(df1['支払期日']) の行をコメントにするとエラーそのものは出なくなりますが、実際は、この例以外にも同様のエラーが出ております。

例えは
df1['消込額'].mask((df1['建物コード']==seikyu_bcd) & (df1['請求番号']==seikyu_no1) & (df1['初回請求番号']==seikyu_no2),1000.0,inplace=True)
の箇所でも、実際のプログラムでは以下のエラーがでます。
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
return self._update_inplace(result)
C:\Program Files\Python39\lib\site-packages\pandas\core\indexing.py:1817: 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

データやロジックを切り出して(実データのため)以下の例を作成しましたが、この場合エラーになりませんでした。
プログラムの何かが悪い可能性がありますが、抽出された行数で動きが異なる様に思いますので、何か手掛かりがあれば
ご教授頂きたくお願い致します。

python

1import pandas as pd 2from io import StringIO 3import itertools 4 5s = """建物コード,建物名称,法人コード,法人名,法人カナ名,送付先法人名,摘要,送付先,請求月,請求番号,初回請求月,初回請求番号,請求書発行日,支払期日,未収金総額,送金額,消費税,その他,備考,番号,消込額 600006601,建物1,0047608,株式会社 パイソン,パイソン,パイソン,摘要1,送付先1,2021-10-01 00:00:00,2110004439,2021-10-01 00:00:00,2110004439-001,2021-10-06 00:00:00,2021-10-31 00:00:00,406056,0,0,0,0,4,9000 700006602,建物1,0047608,株式会社 パイソン,パイソン,パイソン,摘要2,送付先2,2021-10-01 00:00:00,2110004439,2021-10-01 00:00:00,2110004439-001,2021-10-06 00:00:00,2021-10-31 00:00:00,406056,0,0,0,0,4,9000 800006603,建物1,0047608,株式会社 パイソン,パイソン,パイソン,摘要3,送付先3,2021-10-01 00:00:00,2110004439,2021-10-01 00:00:00,2110004439-001,2021-10-06 00:00:00,2021-10-31 00:00:00,406056,0,0,0,0,4,9000 9""" 10df2 = pd.read_csv(StringIO(s)) 11df2[['建物コード','法人コード','請求番号']] = (df2[['建物コード','法人コード','請求番号']]).astype(str) 12df2['建物コード'] = df2['建物コード'].astype(str).str.zfill(8) 13#df1 = df2 14 15seikyu_bcd = "00006601" 16seikyu_no1 = "2110004439" 17seikyu_no2 = "2110004439-001" 18 19df1 = df2.query('建物コード == @seikyu_bcd & 請求番号 == @seikyu_no1 & 初回請求番号 == @seikyu_no2', engine='python') 20 21df1.reset_index(inplace=True,drop=True) 22 23df1['請求書発行日'] = df1['請求書発行日'].fillna(df1['支払期日']) 24df1 = df1.fillna(0) 25 26df1['消込額'].mask((df1['建物コード']==seikyu_bcd) & (df1['請求番号']==seikyu_no1) & (df1['初回請求番号']==seikyu_no2),1000.0,inplace=True) 27 28df1.iloc[0,15] = 10.0 29 30df1

上記の場合、1行目のみ抽出され、以下のエラーが出ますが、元データの建物コードを全て、「00006601」にすると
3行抽出されエラーはでません。

C:\Users\hoge hoge\AppData\Local\Temp;/ipykernel_18068/3028635589.py:32: 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
df1['請求書発行日'] = df1['請求書発行日'].fillna(df1['支払期日'])

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

pandas/pandas/core/generic.py に書いてある様にすると良さそうです。

This technically need not raise SettingWithCopy if both are view

(which is not # generally guaranteed but is usually True. However,

this is in general not a good practice and we recommend using .loc.

df.iloc[0:5]['group'] = 'a'

python

1# df1['請求書発行日'] = df1['請求書発行日'].fillna(df1['支払期日']) 2df1.iloc[:]['請求書発行日'] = df1['請求書発行日'].fillna(df1['支払期日'])

追記

何故、抽出される行数によって変わるのか、df1.iloc[:]['請求書発行日']と記述しないといけないのか

まず、SettingWithCopyWarning というメッセージを出力しているのは _check_setitem_copy() というメソッドなのです。

python

1>>> df1 2 建物コード 建物名称 法人コード ... 30 00006601 建物1 47608 ... 4 5[1 rows x 21 columns] 6 7>>> df1['請求書発行日']._check_setitem_copy() 8sys:1: SettingWithCopyWarning: 9A value is trying to be set on a copy of a slice from a DataFrame. 10Try using .loc[row_indexer,col_indexer] = value instead 11 12See the caveats in the documentation: ... 13 14>>> df1['請求書発行日']._is_copy 15<weakref at 0x7f5ea05dff90; to 'DataFrame' at 0x7f5eb75e7550> 16 17# iloc[:] を作用させることでビュー(参照)になる 18>>> print(df1.iloc[:]['請求書発行日']._check_setitem_copy()) 19None

複数の行が選択される場合はビューになります。

python

1>>> df1 2 建物コード 建物名称 法人コード ... 30 00006601 建物1 47608 ... 41 00006601 建物1 47608 ... 52 00006601 建物1 47608 ... 6 7[3 rows x 21 columns] 8 9>>> print(df1['請求書発行日']._check_setitem_copy()) 10None 11 12>>> print(df1['請求書発行日']._is_copy) 13None

残念ながら、「何故、抽出される行数によって変わるのか」については調べていません。

投稿2021/11/05 17:06

編集2021/11/08 08:08
melian

総合スコア19874

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

km0815.lj

2021/11/05 22:02

回答ありがとうございます。 試してみます。
km0815.lj

2021/11/08 06:26

エラーが出なくなりました。 ありがとうございます。 何故、抽出される行数によって変わるのか、 df1.iloc[:]['請求書発行日']と記述しないといけないのか ご教授頂けると幸いです。
melian

2021/11/08 07:56 編集

追記しましたが、私自身よく理解していないので分かりづらい内容になってしまいました。抽出される行によって変わる原因については折を見て調べます。
km0815.lj

2021/11/08 08:26

ご丁寧な回答ありがとうございます。 初心者のため、なんとなくでしか理解できませんが(申し訳ございません。) とりあえず記述方法が分かりましたので、助かりました。 エラーが無くなりすっきりしました。 >抽出される行によって変わる原因については折を見て調べます。 ありがとうございます。 そのうちこんなことが私にも理解できるようになるのだろうか。。。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問