假设我有以下pandas DataFrame:
df = pd.DataFrame({
'team': ['Warriors', 'Warriors', 'Warriors', 'Rockets', 'Rockets'],
'player': ['Stephen Curry', 'Klay Thompson', 'Kevin Durant', 'Chris Paul', 'James Harden']})
Run Code Online (Sandbox Code Playgroud)
当我尝试对team列进行分组并执行操作时,我得到一个SettingWithCopyWarning:
for team, team_df in df.groupby(by='team'):
# team_df = team_df.copy() # produces no warning
team_df['rank'] = 10 # produces warning
team_df.loc[:, 'rank'] = 10 # produces warning
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
df_team['rank'] = 10
Run Code Online (Sandbox Code Playgroud)
如果我取消注释生成子DataFrame副本的行,我不会收到错误.这通常是最好的做法,以避免这种警告或我做错了什么?
注意我不想编辑原始DataFrame df.此外,我知道这个示例可以更好地完成,但我的用例要复杂得多,需要对原始DataFrame进行分组,并根据不同的DataFrame和该唯一组的规范执行一系列操作.
一旦你理解了这篇文章,并确信你知道如何避免链式索引(通过使用.loc或
iloc),那么你可以关闭SettingWithCopyWarning使用
pd.options.mode.chained_assignment = None并永远不会被这个警告再次打扰.
既然你写了
注意我不想编辑原始DataFrame df
并且您正确地使用.loc分配team_df,很明显您已经知道修改copy(team_df)不会修改原始(df),因此SettingWithCopyWarning这里发出的只是一个麻烦.
该SettingWithCopyWarning在你正确的编码,即使有各种情况出现.loc或.iloc.没有"正确"的编码方式可以避免有时触发SettingWithCopyWarnings.
因此,我将全局关闭此警告
pd.options.mode.chained_assignment = None
Run Code Online (Sandbox Code Playgroud)
我一般不建议使用team_df = team_df.copy()只是为了避免
SettingWithCopyWarnings - 复制数据帧可能会耗费性能,尤其是当数据帧很大或者在循环中多次执行时.
如果您想在一个位置关闭警告,您可以使用
team_df.is_copy = False
Run Code Online (Sandbox Code Playgroud)
它起到同样的作用,但不会造成性能损失.但请注意,is_copy官方Pandas API中未提及,因此可能无法保证在所有未来版本的Pandas中存在或用于此目的.因此,如果稳健性是一个优先事项,但性能不是那么可能使用
team_df = team_df.copy().但我认为经验丰富的Pandas程序员的方法是要么全局关闭警告,要么 - 如果你想要非常小心 - 保留警告,手动检查,但接受它有时会被触发正确的代码.