如何修复 pandas 中的“尝试在 DataFrame 中的切片副本上设置值”警告?

How can I fix the "A value is trying to be set on a copy of a slice from a DataFrame" warning in pandas?

提问人:Bogdan Doicin 提问时间:4/6/2023 更新时间:4/6/2023 访问量:581

问:

我有以下Python函数:

def compute_average_fg_rating(df, mask=''):
    df = df[['HorseId', 'FGrating']]
    if len(mask) == 0:
        df.loc['cumsum'] = df.groupby('HorseId', group_keys=False)['FGrating'].apply(
            lambda x: x.shift(fill_value=0).cumsum())
        return df.loc['cumsum'] / df.groupby('HorseId')['FGrating'].cumcount()
    else:
        return df.loc[mask].groupby('HorseId', group_keys=False)['FGrating'].apply(
            lambda x: x.shift().expanding().mean())

当我尝试运行代码时,我在以下行收到“正在尝试在 DataFrame 的切片副本上设置值”警告:

        df.loc['cumsum'] = df.groupby('HorseId', group_keys=False)['FGrating'].apply(
            lambda x: x.shift(fill_value=0).cumsum())

我看不出有问题的代码在哪里。你可以帮我吗?

Python Pandas 数据帧 警告

评论


答:

2赞 Phoenix 4/6/2023 #1

这是因为 df.loc['cumsum'] 不是对 DataFrame 中特定行的引用。在 if 语句中,将其更改为:

cumsum_df = df.groupby('HorseId', group_keys=False)['FGrating'].apply(
            lambda x: x.shift(fill_value=0).cumsum())
df.loc[cumsum_df.index, 'cumsum'] = cumsum_df
        return df['cumsum'] / df.groupby('HorseId')['FGrating'].cumcount()

这应该可以解决您的问题

0赞 Bogdan Doicin 4/6/2023 #2

警告消息指示该操作正在尝试从原始 DataFrame df 而不是原始 DataFrame 本身的切片副本上设置值。df.loc['cumsum'] = ...

当您使用索引或切片选择原始 DataFrame 的子集,然后就地修改该子集时,可能会发生这种情况。在某些情况下,pandas 会返回子集的副本,而不是原始 DataFrame 的视图,尝试修改此副本可能会导致意外行为。

在本例中,问题出在行 上,该行通过仅选择列“HorseId”和“FGrating”来创建一个新的 DataFrame,该 DataFrame 是原始 df 的子集。这将创建子集的副本,而不是原始 DataFrame 的视图。df = df[['HorseId', 'FGrating']]

若要修复警告消息,可以修改代码以避免创建 DataFrame 的副本。执行此操作的一种方法是使用访问器在同一操作中同时选择行和列:loc

df = df.loc[:, ['HorseId', 'FGrating']]

这将选择所有行 (:) 以及列“HorseId”和“FGrating”。通过使用 loc 访问器,可以确保所选内容返回原始 DataFrame 的视图,而不是副本。

通过此更改,修改后的函数将是:

def compute_average_fg_rating(df, mask=''):
    df = df.loc[:, ['HorseId', 'FGrating']]
    if len(mask) == 0:
        df.loc['cumsum'] = df.groupby('HorseId', group_keys=False)['FGrating'].apply(
            lambda x: x.shift(fill_value=0).cumsum())
        return df.loc['cumsum'] / df.groupby('HorseId')['FGrating'].cumcount()
    else:
        return df.loc[mask].groupby('HorseId', group_keys=False)['FGrating'].apply(
            lambda x: x.shift().expanding().mean())

这应该可以解决警告消息。