pandas:使用 groupby 的操作 yield SettingWithCopyWarning
Posted
技术标签:
【中文标题】pandas:使用 groupby 的操作 yield SettingWithCopyWarning【英文标题】:pandas: operations using groupby yield SettingWithCopyWarning 【发布时间】:2017-12-19 22:13:39 【问题描述】:假设我有以下 pandas DataFrame:
df = pd.DataFrame(
'team': ['Warriors', 'Warriors', 'Warriors', 'Rockets', 'Rockets'],
'player': ['Stephen Curry', 'Klay Thompson', 'Kevin Durant', 'Chris Paul', 'James Harden'])
当我尝试在 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
如果我取消注释生成子数据帧副本的行,我不会收到错误消息。这通常是避免此警告的最佳做法还是我做错了什么?
注意我不想编辑原始 DataFrame df
。我也知道这个例子可以做得更好,但我的用例要复杂得多,需要对原始 DataFrame 进行分组,并根据不同的 DataFrame 和该唯一组的规范执行一系列操作。
【问题讨论】:
【参考方案1】:一旦你摸到this article 并且是
确信您知道如何避免链式索引(通过使用 .loc
或
iloc
) 然后你可以关闭SettingWithCopyWarning
pd.options.mode.chained_assignment = None
,再也不会被这个警告打扰了。
自从你写了
注意我不想编辑原始 DataFrame df
并且您正确地使用.loc
分配给team_df
,很明显您
已经知道修改副本(team_df
)不会修改原来的
(df
),所以这里发出的SettingWithCopyWarning
只是一个麻烦。
SettingWithCopyWarning
出现在您所处的各种情况下
正确编码,即使使用 .loc
或 .iloc
。没有“正确”的编码方式
这避免了有时触发SettingWithCopyWarning
s。
因此,我将在全局范围内关闭此警告
pd.options.mode.chained_assignment = None
我一般不建议使用team_df = team_df.copy()
只是为了避免
SettingWithCopyWarning
s -- 复制数据框可能会消耗
性能特别是当数据帧很大或循环执行多次时。
如果你想turn off the warning in just one location,你可以使用
team_df.is_copy = False
它具有相同的目的,但不会消耗性能。但是请注意,
is_copy
在 Pandas 官方 API 中没有提到,所以可能没有
保证在所有未来版本中存在或用于此目的
熊猫。因此,如果稳健性是优先考虑但性能不是那么可能使用
team_df = team_df.copy()
。但我认为对于有经验的人来说更合理的方式
Pandas 程序员要做的是要么全局关闭警告,要么 - 如果你
要非常小心——保留警告,手动检查它们,但接受
它有时会被正确的代码触发。
【讨论】:
@piRSquared:我从Alexander、here了解到the article。 如您所料,is_copy
在 Pandas v0.24.2 中已被弃用,但现在有 _is_copy
。【参考方案2】:
pandas split apply combine docs 在这方面不是很好。这应该为您指明正确的方向
def apply_fun(team_df):
team_df['rank'] = 10
return team_df
df.groupby('team').apply(apply_fun)
df['column_rank'] = df.groupby('team')['column'].transform(lambda x: x.rank())
【讨论】:
以上是关于pandas:使用 groupby 的操作 yield SettingWithCopyWarning的主要内容,如果未能解决你的问题,请参考以下文章
数据分析—Pandas 中的分组聚合Groupby 高阶操作
python处理数据的风骚操作[pandas 之 groupby&agg]