我喜欢 pandas 并且多年来一直在使用它,并且非常有信心我可以很好地处理如何对数据帧进行子集化以及适当地处理视图与副本(尽管我使用了很多断言来确定)。我也知道有很多关于 SettingWithCopyWarning 的问题,例如如何处理 Pandas 中的 SettingWithCopyWarning? 以及一些关于在它发生时绕开你的头的最新指南,例如了解 Pandas 中的 SettingWithCopyWarning。
但我也知道具体的事情,比如这个答案中的引用不再出现在最新的文档中(0.22.0
.iloc
最近,在教 pandas 让新手完成关于避免链式索引(和使用/ )等非常基本的 Python 知识之后.loc
,我仍然很难提供一般的经验法则来了解何时需要注意SettingWithCopyWarning
(例如,何时忽略它是安全的)。
我个人发现,根据某些规则(例如切片或布尔操作)对数据框进行子集化,然后独立于原始数据框修改该子集的特定模式是比文档建议的更常见的操作。在这种情况下,我们想要修改副本而不是原始版本,并且警告对新手来说是令人困惑/害怕的。
我知道提前知道何时返回视图与副本并非易事,例如
,Pandas 使用什么规则来生成视图与副本?
在 Pandas 中检查数据框是复制还是查看
因此,我正在寻找更一般(初学者友好)问题的答案:对子集数据帧执行操作何时会影响创建它的原始数据帧,它们何时独立?.
我在下面创建了一些我认为合理的案例,但我不确定我是否遗漏了“陷阱”,或者是否有更简单的方法来思考/检查这一点。我希望有人可以确认我对以下用例的直觉与我上面的问题有关。
import pandas as pd
df1 = pd.DataFrame({'A':[2,4,6,8,10],'B':[1,3,5,7,9],'C':[10,20,30,40,50]})
1) 警告:无
原件更改:无
# df1 will be unaffected because we use .copy() method explicitly
df2 = df1.copy()
#
# Reference: docs
df2.iloc[0,1] = 100
2)警告:是(我不太明白为什么)
原来的变化:否
# df1 will be unaffected because .query() always returns a copy
#
# Reference:
# https://stackoverflow.com/a/23296545/8022335
df2 = df1.query('A < 10')
df2.iloc[0,1] = 100
3)警告:是
原始更改:否
# df1 will be unaffected because boolean indexing with .loc
# always returns a copy
#
# Reference:
# https://stackoverflow.com/a/17961468/8022335
df2 = df1.loc[df1['A'] < 10,:]
df2.iloc[0,1] = 100
4) 警告:无
原件更改:无
# df1 will be unaffected because list indexing with .loc (or .iloc)
# always returns a copy
#
# Reference:
# Same as 4)
df2 = df1.loc[[0,3,4],:]
df2.iloc[0,1] = 100
5) 警告:否
原件更改:是(让新手感到困惑,但有道理)
# df1 will be affected because scalar/slice indexing with .iloc/.loc
# always references the original dataframe, but may sometimes
# provide a view and sometimes provide a copy
#
# Reference: docs
df2 = df1.loc[:10,:]
df2.iloc[0,1] = 100
tl;dr
从原始数据帧创建新数据帧时,更改新数据帧:当使用 .loc/.iloc 的标量/切片索引创建新数据帧
时,将更改原始数据帧。使用 .loc进行布尔索引时
不会更改原始索引,或用于创建新数据帧.query()
.copy()