Pandas深拷贝嵌套列仍影响原DataFrame?求独立修改方案
Pandas中
deep=True复制后修改嵌套列仍影响原DataFrame的问题及解决方法 问题说明
使用df.copy(deep=True)复制包含嵌套字典/列表的DataFrame时,修改副本的嵌套列字段值会同步影响原DataFrame。即使不是重命名字段,仅修改嵌套字段的数值,原DataFrame的对应数据也会被改变。
示例代码及现象:
import pandas as pd df = pd.DataFrame({'a': [{'field': [1,2,3.0]}, {'field': [1,2,4.0]}, {'field': [1,2,5.0]}]}) print('原DataFrame: \n', df['a']) def integer_converter(x): x['a']['field'] = [int(i) for i in x['a']['field']] df2 = df.copy(deep=True) df2.apply(integer_converter, axis=1) print('修改后的df2: \n', df2['a']) print('再次打印原DataFrame: \n', df['a'])
输出结果显示:原df的嵌套数组也被转为整数类型,说明副本和原DataFrame的嵌套数据仍共享内存。
原因分析
Pandas的deep=True复制仅对DataFrame的顶层结构做深度复制,但对于嵌套的Python可变对象(如字典、列表),只会复制对象的引用而非对象本身。也就是说,嵌套的字典/列表依然和原DataFrame共享内存空间,修改副本里的嵌套对象时,原对象会同步被修改。
解决方案
方法1:手动对嵌套对象做深度复制
使用Python标准库的copy.deepcopy()对嵌套列的每个元素单独做深度复制,彻底切断与原数据的引用关联:
import pandas as pd import copy df = pd.DataFrame({'a': [{'field': [1,2,3.0]}, {'field': [1,2,4.0]}, {'field': [1,2,5.0]}]}) print('原DataFrame: \n', df['a']) # 先复制DataFrame,再对嵌套列做深度复制 df2 = df.copy() df2['a'] = df2['a'].apply(copy.deepcopy) def integer_converter(x): x['a']['field'] = [int(i) for i in x['a']['field']] df2.apply(integer_converter, axis=1) print('修改后的df2: \n', df2['a']) print('再次打印原DataFrame: \n', df['a'])
方法2:修改时创建新的嵌套对象
在处理数据时,不直接修改原嵌套对象的引用,而是创建新的字典/列表替换原有值:
import pandas as pd df = pd.DataFrame({'a': [{'field': [1,2,3.0]}, {'field': [1,2,4.0]}, {'field': [1,2,5.0]}]}) print('原DataFrame: \n', df['a']) def integer_converter(x): # 创建新字典,避免修改原引用 new_nested = x['a'].copy() new_nested['field'] = [int(i) for i in new_nested['field']] return new_nested df2 = df.copy(deep=True) df2['a'] = df2.apply(integer_converter, axis=1) print('修改后的df2: \n', df2['a']) print('再次打印原DataFrame: \n', df['a'])
方法3:展开嵌套结构后复制(适用于规则嵌套)
将嵌套数据展开为扁平DataFrame,复制后再还原嵌套结构,彻底隔离数据:
import pandas as pd df = pd.DataFrame({'a': [{'field': [1,2,3.0]}, {'field': [1,2,4.0]}, {'field': [1,2,5.0]}]}) print('原DataFrame: \n', df['a']) # 展开嵌套结构为扁平表 df_flat = pd.json_normalize(df['a'], record_prefix='a.') df2_flat = df_flat.copy(deep=True) # 修改数据 df2_flat['a.field'] = df2_flat['a.field'].apply(lambda x: [int(i) for i in x]) # 还原嵌套结构 df2 = pd.DataFrame({'a': df2_flat.to_dict('records')}) df2['a'] = df2['a'].apply(lambda x: {k.replace('a.', ''): v for k, v in x.items()}) print('修改后的df2: \n', df2['a']) print('再次打印原DataFrame: \n', df['a'])
内容的提问来源于stack exchange,提问作者Eugenio.Gastelum96
相关产品推荐
相关产品推荐

