17

Have a general question on assignments with indexing/slicing using .loc.

Assume the below DataFrame, df:

df:    
    A   B   C
0   a   b   
1   a   b   
2   b   a   
3   c   c   
4   c   a   

code to reproduce:

df = pd.DataFrame({'A':list('aabcc'), 'B':list('bbaca'), 'C':5*[None]})

I create df1 using:

df1=df.loc[df.A=='c']

df1:
    A   B   C
3   c   c   
4   c   a   

I then assign a value to C based upon a value in B using:

df1.loc[df1.B=='a','C']='d'

The assignment works, but I receive a SettingWithCopy warning. Am I doing something wrong or is this the expected functionality? I thought that using .loc would avoid chained assignment. Is there something that I am missing? I am using Pandas 14.1

Yuval Atzmon
  • 5,645
  • 3
  • 41
  • 74
MattB
  • 1,325
  • 2
  • 11
  • 8
  • 1
    I'm not 100% sure if this is a bug but running your code I see that `df1` is modified but `df` is not which is not what you are intending. You've assigned `df1` to be a reference to a slice of your `df` but now performing the `loc` assignment has only modified `df1`, it smells like a bug to me but I am not 100% sure if this is intended or not – EdChum Aug 25 '14 at 16:31
  • 1
    In this case it was my intention to only modify df1, was just curious as to why I was receiving the SettingWithCopy warning when doing so, but I think you actually answered it. In the above, df1 is a reference to a slice of df. If I create df1 using df1=pandas.DataFrame(df.loc[df.A=='c']) then the warning goes away. – MattB Aug 25 '14 at 17:15
  • 3
    the point here is that you are modifying a frame that is in effect a slice of another. you normally need to copy to avoid this warning as you can sometimes operate on a copy. – Jeff Aug 25 '14 at 17:27
  • 8
    Rather than just taking a reference, you could be more explicit in your code and do `df1=df.loc[df.A=='c'].copy()` this will make it clear your intentions and not raise a warning. – EdChum Aug 25 '14 at 18:58

1 Answers1

11

@EdChum answer in comments to OP has solved the issue. i.e. replace

df1=df.loc[df.A=='c']

with

df1=df.loc[df.A=='c'].copy()

this will make it clear your intentions and not raise a warning

Yuval Atzmon
  • 5,645
  • 3
  • 41
  • 74