1

I have this program for demonstration:

import pandas as pd

d = {'foo':[100, 111, 222], 
     'bar':[333, 444, 555]}
df = pd.DataFrame(d)

list = [333,444]

dferg = df.loc[df.bar.isin(list)]

dferg['test'] = 123

I get the warning:

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: http://pandas.pydata.org/pandas- 
docs/stable/indexing.html#indexing-view-versus-copy
  dferg['test'] = 123

when i change:

dferg = df.loc[df.bar.isin(list)]

to

dferg = df.loc[df.bar.isin(list)].copy()

there is no more warning. But is this the best way?

Egirus Ornila
  • 1,234
  • 4
  • 14
  • 39
  • Well looks like they are deprecating "*the best way*" which was setting `dferg.is_copy = False` so looks like copying again is the new best way. – ayhan Jun 17 '18 at 14:21
  • Possible duplicate of [How to deal with SettingWithCopyWarning in Pandas?](https://stackoverflow.com/questions/20625582/how-to-deal-with-settingwithcopywarning-in-pandas) – DJK Jun 17 '18 at 14:30

1 Answers1

2

dferg = df.loc[df.bar.isin(list)] is a get operation which can return either a view or a copy. Calling .copy() is explicitly telling it's actually a copy, thus no warning is raised. dferg['test'] = 123 modifies the original df too, so pandas warns you in case you might want to work with a copy instead of a view.

Think about whether you want the original DataFrame df to be modified by what ever assignments you do to dferg. If you actually want to modify the first DataFrame, put everything in a single .loc call:

df.loc[df.bar.isin(list), 'test'] = 123 # sets 123 in df

else, just explicitly call copy like you said:

dferg = df.loc[df.bar.isin(list)].copy()
dferg['test'] = 123 # ONLY modifies dferg, not original df
Tomas Farias
  • 1,293
  • 1
  • 14
  • 18