在更改从另一个数据帧的切片创建的数据帧时,是否应该始终使用.copy()方法显式生成副本?否则,我将收到SettingWithCopy警告。然而,在这种情况下,它并没有导致任何麻烦;原始数据帧保持不变。
>>> import pandas as pd
>>> df = pd.DataFrame([[6,3,2],[4,3,2],[5,4,2],[4,3,5]], columns=['a', 'b', 'c'])
>>> df
a b c
0 6 3 2
1 4 3 2
2 5 4 2
3 4 3 5
>>> df2 = df.loc[df.a<6, :]
>>> df2.loc[df2.b==3, 'b'] = 99
/usr/lib/python3/dist-packages/pandas/core/indexing.py:117: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
self._setitem_with_indexer(indexer, value)
__main__:1: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
>>> df
a b c
0 6 3 2
1 4 3 2
2 5 4 2
3 4 3 5
>>> df2
a b c
1 4 99 2
2 5 4 2
3 4 99 5
或者,如果我执行以下操作,则不会收到任何警告。
>>> df2 = df.loc[df.a<6, :].copy()
>>> df2.loc[df2.b==3, 'b'] = 99
>>> df2
a b c
1 4 99 2
2 5 4 2
3 4 99 5
>>> df
a b c
0 6 3 2
1 4 3 2
2 5 4 2
3 4 3 5
后者更好吗?(因此我没有得到任何警告)。在什么意义上?是因为我确信df2是一个副本,因此不能更改原始数据帧df吗?
如果用户对命令的解释存在歧义,则会出现SettingWithCopyWarning。在第一种情况下,Panda很清楚应该将值分配给df2
。但是,尚不清楚用户是否期望值分配传播到df
本身,这就是引发警告的原因。在内部,panda使用数据帧的_is_copy
属性对此进行跟踪。创建df2
时,_is_copy
属性存储对df
的弱引用。
In [1]: import pandas as pd
In [2]: df = pd.DataFrame([[6,3,2],[4,3,2],[5,4,2],[4,3,5]], columns=['a', 'b', 'c'])
In [3]: df2 = df.loc[df.a<6, :]
In [4]: df2._is_copy
Out[4]: <weakref at 0x7f0dae5a3770; to 'DataFrame' at 0x7f0daef08850>
在第二种情况下,df2
被显式创建为df
的副本,因此panda不会将weakref存储到df
。
In [5]: df2 = df.loc[df.a<6, :].copy()
In [6]: df2._is_copy
In [7]: print(df2._is_copy)
None
对df2
所做的任何操作都不会影响其他数据帧,因此在值分配中不存在歧义,因此不需要引发SettingWithCopyWarning。
来源:
- 熊猫文档:http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-查看与复制
- https://tnwei.github.io/posts/settings-with-copy-warning-pandas/