使用pandas时df.copy()结合remove为何会修改原DataFrame?
原因分析
问题核心出在原地修改列表对象的操作逻辑上:
- 虽然
deepcopy或df.copy(deep=True)会递归复制DataFrame中的列表对象,但你使用new_df['name'][i].remove(j)是对列表进行原地修改,这种操作依赖于对象引用,一旦遍历逻辑出现异常(比如遍历列表的同时删除元素),再加上交互式环境中可能存在的变量复用问题,容易引发引用混淆,导致你误以为原df被修改。 - 更关键的是,Pandas的索引机制在处理object类型列时,直接原地修改元素可能会绕过深拷贝的隔离,出现意外的关联。
解决方法
不要原地修改列表,而是通过重新赋值新列表的方式修改副本,彻底切断与原df中列表对象的关联:
方法1:循环构造新列表并赋值
根据你想要保留的元素逻辑(原代码最终保留了列表的第2个元素),直接生成新列表并赋值给副本的对应单元格:
import pandas as pd import copy data = {"name": [["Sally", "EYE", "FACE"], ["Mary", "John"]], "qualified": [True, False]} df = pd.DataFrame(data) new_df = copy.deepcopy(df) # 遍历副本,重新构造name列的列表 for i in range(len(new_df)): # 保留列表索引为1的元素(对应原代码的最终结果) new_list = [new_df['name'][i][1]] # 使用.loc赋值,确保修改的是副本的独立对象 new_df.loc[i, 'name'] = new_list print("\nNEWDF: ", new_df) print("\nDF: ", df)
方法2:用apply生成新列
更简洁的方式是用apply直接生成新的name列,避免循环:
import pandas as pd import copy data = {"name": [["Sally", "EYE", "FACE"], ["Mary", "John"]], "qualified": [True, False]} df = pd.DataFrame(data) new_df = copy.deepcopy(df) # 用apply生成新的name列,保留每个列表的第2个元素 new_df['name'] = new_df['name'].apply(lambda x: [x[1]]) print("\nNEWDF: ", new_df) print("\nDF: ", df)
这两种方法都会生成全新的列表对象赋值给副本,彻底避免对原df中列表对象的任何修改,确保原df保持初始状态。
内容的提问来源于stack exchange,提问作者korez14
相关产品推荐
相关产品推荐

