对pandas groupby对象重复执行agg修改原始dataframe的问题求解
问题原因
- 核心问题出自可变对象的引用传递:你存储在DataFrame中的字典、列表都属于Python可变对象,聚合函数里
out[k] = v的写法是直接把原列表的引用赋值给out字典的键,后续执行out[k].extend(v)操作时,会直接修改原DataFrame中存储的列表本身,而非操作独立副本。 - 你对深拷贝的使用方式存在错误:
cp.deepcopy(grouped['probe_dict'])没有实际作用,groupby对象仅持有底层数据的引用,拷贝它不会复制实际数据;即便你对DataFrame做了深拷贝,只要聚合函数里直接操作原列表引用,还是会修改你传入的df数据(传入副本则改副本,传入原df则改原df)。
解决方法
最优方案:修改聚合函数,从根源避免修改原对象
赋值时直接拷贝列表,不再引用原DataFrame中的列表对象,修改后的函数如下:
def merge_probe_trial_dicts(x, only_last=None): """ 传入pandas groupby聚合的函数,用于按被试和任务合并字典 参数: ========================= x: agg方法传入的分组数据 only_last (int): 每个转换仅保留最后n个探针试次 """ out = {} for d in x.dropna(): for k, v in d.items(): if k not in out: # 新增列表拷贝操作,不直接引用原列表 out[k] = v.copy() else: out[k].extend(v) if only_last: for k, v in out.items(): out[k] = v[-only_last:] return out
辅助优化:调整深拷贝的使用逻辑
不需要拷贝groupby对象,如果需要完全隔离原DataFrame,可以提前单独拷贝DataFrame再做分组,示例代码如下:
import copy as cp from functools import partial # 单独拷贝DataFrame,避免后续操作影响原数据 df_copy = cp.deepcopy(df4) grouped = df_copy.groupby(['subject','task_nr']) mptd_only30 = partial(merge_probe_trial_dicts, only_last=30) # 直接对分组后的列执行聚合即可,不需要拷贝groupby对象 mergag = grouped['probe_dict'].agg(mptd_only30)
内容的提问来源于stack exchange,提问作者user3235916
相关产品推荐
相关产品推荐

