了解Pandas的SettingWithCopyWarning警告

4

我有以下代码,但不太明白为什么会出现警告。我已经阅读了文档,但仍然无法理解为什么使用会导致警告。如有任何见解,请指教。

>>> df = pandas.DataFrame({'a': [1,2,3,4,5,6,7], 'b': [11,22,33,44,55,66,77]})
>>> reduced_df = df[df['a'] > 3]
>>> reduced_df
   a   b
3  4  44
4  5  55
5  6  66
6  7  77
>>> reduced_df['a'] /= 3

Warning (from warnings module):
   File "__main__", line 1
SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead
>>> reduced_df
          a   b
3  1.333333  44
4  1.666667  55
5  2.000000  66
6  2.333333  77

这行代码 reduced_df = df[df['a'] > 3] 的意思是 reduced_df 是从 df 中切片出来的副本,你现在试图对其进行赋值,因此会出现警告。你可以像这样显式地复制:reduced_df = df[df['a'] > 3].copy() 或者如果你想修改原始的 df,那么可以使用 df.loc[df['a']>3,'a'] = df['a']/3 - EdChum
我猜警告存在的原因是,通常你期望在Python中foo = bar意味着foo是对bar的引用,所以如果你修改了foo,那么你期望bar也会改变,但这里并非如此。 - EdChum
所以这个警告告诉我,对于reduced_df所做的任何更改不会显示在df中,因为reduced_df = df[df['a'] > 3]这行代码产生了一个深拷贝? - derNincompoop
是的,但因为您在这里没有明确说明,它会警告您将发生什么,就像我说的那样,如果您执行reduced_df = df[df['a'] >3].copy(),那么就不会有警告,因为您现在已经明确地进行了深度复制。 - EdChum
太好了 - 它进行深拷贝的事实是我没有理解的。 - derNincompoop
1个回答

6

这里的警告是告诉你,尽管外观上你的reduced_df是对df的切片的引用,但实际上它是一个副本。这与通常的语义不同,人们会期望这会导致一个引用,并且对该引用的修改将影响该引用和原始对象(当然只针对可变对象):

In [14]:

foo = [0]
bar = foo
bar.append(1)
print(foo,bar)
[0, 1] [0, 1]

如果您想修改数据框中的特定部分,则应按照警告建议进行操作:

In [18]:

df.loc[df['a']>3,'a'] =df['a']/3
df
Out[18]:
          a   b
0  1.000000  11
1  2.000000  22
2  3.000000  33
3  1.333333  44
4  1.666667  55
5  2.000000  66
6  2.333333  77

或者通过调用copy()方法显式地进行深度复制,并修改复制后的内容,而不会生成任何警告:

In [20]:

reduced_df = df[df['a'] > 3].copy()
reduced_df['a'] /=3
reduced_df
Out[20]:
          a   b
3  1.333333  44
4  1.666667  55
5  2.000000  66
6  2.333333  77

In [21]:
# orig df is unmodified
df
Out[21]:
   a   b
0  1  11
1  2  22
2  3  33
3  4  44
4  5  55
5  6  66
6  7  77

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接