LoginSignup
0
0

More than 1 year has passed since last update.

DataFrameの計算でWarningが出た!その理由は

Posted at

DataFrame同士で計算を行っていると、次の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
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

Warningの意味は、「もとのDataFrameからコピーした。(=もとのDFは上書きしなかった)」というものです。
しかし、欲しい結果は得られているのではないでしょうか。
結果は正しいのですが、Pythonは「この結果は、あなたが望んだ結果ではないかもしれないので、注意して」と言っているのです。

※ここではDataFrameを「df」(またはDF)と表記します。
※ここで使用したcsvファイル、コード全文は、ページ下部の参考ページのリンクから参照可能です。

内容

【どんな時に起きるか】

これは、例えば、%表示の変換で、「1.00(%)」となっているものを数値「0.01」に同じカラム名で変換(上書き)しようと、

df2['pct'] = df2['pct'] / 100

と書いた場合に起きると思います。それは、コードを辿ると、df2が他のDFを参照し

df2 = df1[['clm0', 'clm1']]

のように書いているのではないでしょうか?

【原因】

これは chained indexing と呼ばれるものです。

dfを連鎖的にカラム名を指定して参照(複製)した場合に起きます。
例えば、df1が所与の時、新しいdf2に対して、

df2 = df1[['clm0', 'clm1']]と書いて、更にdf2['clm0'] =1のように、

辿った先の、元のdf1を、df1のカラム名を使って上書きする(上書きするのと同じコードを書いた)ような場合に起きます。

df2 = df1と書けば、df2['clm0']=1(カラム’clm0’を全部1にする)と書いても問題は起きません。それは、df1の全てがdf2に複製され、df2をいじると、df1も同時に上書きされるからです。

ところが、カラム名を指定して、df2 = df1[['clm0', 'clm1']]と書くと、df2には写しが渡されますが、ここでdf1に存在するカラム名’clm0’を指定してdf2の方からdf2['clm0']=1と書くと、Pythonはdf1は上書きしない、という判断をします。

本来、df2 = df1という書き方は、df2をいじれば、df1も上書きする、という仕様です。しかし、df2['clm0']=1と書くと、この仕様とは異なるので、Warningを出すと思われます。

Warningの指示通り、df.loc[]を使っても(例えば、df.loc[:,'pct'])、同じWarningが出るはずです。

まず、仕様を確認します。

import pandas as pd
f1 = r'C:\Users\shilabo\Documents\SHiLABO_python\a004_007a.csv'
df1 = pd.read_csv(f1)

#1.1(a) example
df2A = pd.read_csv(f1)
df2a = df2A
df2a['clm0'] = 99
print('#df2a\n', df2a)
#df2a
#    clm0  clm1  clm2  clm3
#0    99    -1    12   105
#1    99    -2    22   205
#2    99    -3    32   305
#3    99    -4    42   405
#4    99    -5    52   505

print('#df2A\n', df2A)
#df2A
#    clm0  clm1  clm2  clm3 #<=df2Aも'clm0'が上書きされる。
#0    99    -1    12   105
#1    99    -2    22   205
#2    99    -3    32   305
#3    99    -4    42   405
#4    99    -5    52   505
view rawa004_007_02.py hosted with  by GitHub

次にWaningを再現します。

df2B = pd.read_csv(f1)
df2b = df2B[['clm0', 'clm1']]
df2b['clm0'] = 99
print('#df2b\n',df2b) 
#df2b               #<=df2bはWarningが出て、上書きされる。
#    clm0  clm1
#0    99    -1
#1    99    -2
#2    99    -3
#3    99    -4
#4    99    -5
#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

print('#df2B\n',df2B)
#df2B
#    clm0  clm1  clm2  clm3 #<=df2Bは'clm0'が上書きされない。
#0     1    -1    12   105
#1     2    -2    22   205
#2     3    -3    32   305
#3     4    -4    42   405
#4     5    -5    52   505

【解決方法】

  1. 同じ名前のカラム名で、結果を入れた新しいカラムを作るのを「避ければ」、このWarningは回避できます。
    または、
  2. 同じカラム名にしたければ、以下のように、df2 = df1['clm0'].copy()と書いて、コピーである事を明確にすれば、Warningは出ません。
df2C = pd.read_csv(f1)
df2c = df2C[['clm0', 'clm1']].copy() #.copy()とする。
df2c['clm0'] = 99
print('#df2c\n',df2c)
#df2c
#    clm0  clm1 #<=df2cで'clm0'を上書きしてもWarningは出ない。
#0    99    -1
#1    99    -2
#2    99    -3
#3    99    -4
#4    99    -5

print('#df2C\n',df2C)
#df2C
#    clm0  clm1  clm2  clm3 #<=df2Cは上書きされない。
#0     1    -1    12   105
#1     2    -2    22   205
#2     3    -3    32   305
#3     4    -4    42   405
#4     5    -5    52   505

勿論、Warningの内容を分かっていて使っていれば、多くの場合、問題ありません。

参考ページ

  • 実践で使うPythonの技術が掲載されています。書籍のように構成されています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0