如何修复Pandas中‘试图在DataFrame切片副本上赋值’警告?
解决Pandas中“A value is trying to be set on a copy of a slice from a DataFrame”警告
问题背景
编写了如下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())
运行时在以下代码行收到警告:
df.loc['cumsum'] = df.groupby('HorseId', group_keys=False)['FGrating'].apply( lambda x: x.shift(fill_value=0).cumsum())
问题原因
第一行df = df[['HorseId', 'FGrating']]是对原DataFrame的切片操作,Pandas返回的可能是原数据的视图(view)而非独立的副本(copy)。后续对df.loc['cumsum']赋值时,Pandas无法确定你是否要修改原DataFrame,因此抛出该警告。
解决方法
方法1:显式创建副本
在切片后调用.copy(),确保操作的是独立的DataFrame副本:
def compute_average_fg_rating(df, mask=''): # 显式创建副本,切断与原DataFrame的关联 df = df[['HorseId', 'FGrating']].copy() 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())
方法2:避免修改切片后的DataFrame
直接计算所需中间结果,跳过向切片DataFrame添加行的步骤,从根源避免警告:
def compute_average_fg_rating(df, mask=''): df_slice = df[['HorseId', 'FGrating']] if len(mask) == 0: # 直接计算累加和与计数,无需修改df_slice cumsum = df_slice.groupby('HorseId', group_keys=False)['FGrating'].apply( lambda x: x.shift(fill_value=0).cumsum()) count = df_slice.groupby('HorseId')['FGrating'].cumcount() return cumsum / count else: return df_slice.loc[mask].groupby('HorseId', group_keys=False)['FGrating'].apply( lambda x: x.shift().expanding().mean())
说明
两种方法都能解决警告问题:方法1通过显式副本明确操作对象;方法2简化逻辑,避免对视图的修改操作,同时让代码更简洁。
内容的提问来源于stack exchange,提问作者Bogdan Doicin
相关产品推荐
相关产品推荐

