我喜欢 pandas 并且已经使用它很多年了,并且非常有信心我能够很好地掌握如何对数据帧进行子集化并适当地处理视图与副本(尽管我使用了很多断言来确保)。我还知道有很多关于SettingWithCopyWarning的问题,例如如何处理Pandas中的SettingWithCopyWarning? https://stackoverflow.com/questions/20625582/how-to-deal-with-settingwithcopywarning-in-pandas以及最近一些很棒的指南,帮助您在发生这种情况时保持头脑清醒,例如理解pandas中的SettingWithCopyWarning https://www.dataquest.io/blog/settingwithcopywarning/.
但我也知道具体的事情,比如引用这个答案 https://stackoverflow.com/a/17961468/8022335不再出现在最新的文档中(0.22.0
)并且多年来许多事情已被弃用(导致一些不合适的旧答案),并且事情是持续改变 https://stackoverflow.com/a/34908742/8022335.
最近,在教 pandas 使新手具备非常基本的 Python 通用知识之后,例如避免链式索引(以及使用.iloc
/.loc
),我仍然努力提供一般经验法则知道什么时候需要注意SettingWithCopyWarning
(例如,当可以安全地忽略它时)。
我个人发现,根据某些规则(例如切片或布尔运算)对数据帧进行子集化的特定模式,然后修改该子集,独立于原始数据框,是比文档建议的更常见的操作。在这种情况下我们想要修改副本而不是原始文件而且这个警告让新手感到困惑/害怕。
我知道提前知道何时返回视图与副本并不简单,例如
Pandas 使用什么规则来生成视图和副本? https://stackoverflow.com/questions/23296282/what-rules-does-pandas-use-to-generate-a-view-vs-a-copy
检查数据框是在 Pandas 中复制还是查看 https://stackoverflow.com/questions/26879073/checking-whether-data-frame-is-copy-or-view-in-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 进行标量/切片索引来创建新的数据帧.
Will not改变原来的时候使用 .loc 进行布尔索引,.query()
, or .copy()
用于创建新的数据框