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 并且是 确信您知道如何避免链式索引(通过使用 .lociloc) 然后你可以关闭SettingWithCopyWarning pd.options.mode.chained_assignment = None,再也不会被这个警告打扰了。

自从你写了

注意我不想编辑原始 DataFrame df

并且您正确地使用.loc 分配给team_df,很明显您 已经知道修改副本(team_df)不会修改原来的 (df),所以这里发出的SettingWithCopyWarning 只是一个麻烦。

SettingWithCopyWarning 出现在您所处的各种情况下 正确编码,即使使用 .loc.iloc。没有“正确”的编码方式 这避免了有时触发SettingWithCopyWarnings。

因此,我将在全局范围内关闭此警告

pd.options.mode.chained_assignment = None

我一般不建议使用team_df = team_df.copy() 只是为了避免 SettingWithCopyWarnings -- 复制数据框可能会消耗 性能特别是当数据帧很大或循环执行多次时。

如果你想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 高阶操作

Pandas高级教程之:GroupBy用法

python处理数据的风骚操作[pandas 之 groupby&agg]

pandas 中是不是有与 .groupby 相对的“ungroup by”操作?

Pandas 使用 groupby 和模式填充

Pandas | 18 GroupBy 分组