You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免含列表的Pandas DataFrame深拷贝后修改影响原数据?

Pandas DataFrame含列表列时深拷贝失效的解决办法及原因分析

当Pandas DataFrame的列中每行存储列表时,即便使用copy(deep=True)进行深拷贝,修改新DataFrame中该列的列表元素仍会同步影响原DataFrame。无论通过哪种方式实例化这类列表列,问题都会出现。本文将解答如何避免这种相互影响,以及这是否属于DataFrame使用列表的固有缺陷。


相关代码

import pandas as pd
import numpy as np

df = pd.DataFrame({'Person': ['Jack', 'Bob', 'Alice'], 'Age': [20, 30, 40]})
df['Flavors'] = np.empty((len(df), 0)).tolist()
df['Colors'] = [[] for _ in range(len(df))]
df['Friends'] = [[],[],[]]
print(df)
df2 = df.copy(deep=True)
df2.loc[0, 'Flavors'].append('Apple')
df2.loc[0, 'Colors'].append('Red')
df2.loc[0, 'Friends'].append('Rick')
print(df)
print(df2)

实际输出

Person  Age Flavors Colors Friends
0   Jack   20      []     []      []
1    Bob   30      []     []      []
2  Alice   40      []     []      []
  Person  Age  Flavors Colors Friends
0   Jack   20  [Apple]  [Red]  [Rick]
1    Bob   30       []     []      []
2  Alice   40       []     []      []
  Person  Age  Flavors Colors Friends
0   Jack   20  [Apple]  [Red]  [Rick]
1    Bob   30       []     []      []
2  Alice   40       []     []      []

预期输出

Person  Age Flavors Colors Friends
0   Jack   20      []     []      []
1    Bob   30      []     []      []
2  Alice   40      []     []      []
  Person  Age  Flavors Colors Friends
0   Jack   20  [Apple]     []      []
1    Bob   30       []     []      []
2  Alice   40       []     []      []
  Person  Age  Flavors Colors Friends
0   Jack   20  [Apple]  [Red]  [Rick]
1    Bob   30       []     []      []
2  Alice   40       []     []      []

原因分析

Pandas的deep=True拷贝并非完全意义上的Python深拷贝。对于DataFrame中的对象类型(比如列表),Pandas只会拷贝对象的引用,而不会递归地拷贝对象内部的元素。也就是说,新DataFrame的列是新的Series,但Series中的每个列表元素仍然和原DataFrame的列表指向同一个内存地址,修改列表元素自然会同步影响两个DataFrame。

解决办法

方法1:使用apply+copy逐个复制列表

对所有含列表的列,手动复制每个列表元素,断开与原DataFrame的引用关联:

df2 = df.copy(deep=True)
# 遍历所有列表列,逐个复制内部列表
for col in ['Flavors', 'Colors', 'Friends']:
    df2[col] = df2[col].apply(lambda x: x.copy())

# 此时修改新DataFrame的列表元素不会影响原DataFrame
df2.loc[0, 'Flavors'].append('Apple')
df2.loc[0, 'Colors'].append('Red')
df2.loc[0, 'Friends'].append('Rick')

方法2:用copy.deepcopy递归复制整个DataFrame

直接使用Python标准库的copy.deepcopy,对整个DataFrame进行完全递归的深拷贝:

import copy

df2 = copy.deepcopy(df)

df2.loc[0, 'Flavors'].append('Apple')
df2.loc[0, 'Colors'].append('Red')
df2.loc[0, 'Friends'].append('Rick')

方法3:重构数据结构(推荐)

尽量避免在DataFrame中存储列表这类可变对象,这更符合Pandas处理表格型数据的设计范式。可以将列表拆分为多行(用explode),或者转为JSON字符串存储:

import json
# 将列表转为JSON字符串存储
df['Flavors'] = df['Flavors'].apply(json.dumps)
df['Colors'] = df['Colors'].apply(json.dumps)
df['Friends'] = df['Friends'].apply(json.dumps)

# 拷贝后转回列表修改
df2 = df.copy(deep=True)
flavors_list = json.loads(df2.loc[0, 'Flavors'])
flavors_list.append('Apple')
df2.loc[0, 'Flavors'] = json.dumps(flavors_list)

是否是固有缺陷?

这不能算是严格意义上的"缺陷",而是Pandas设计上的权衡。Pandas核心是处理标量值的表格数据,存储可变对象(如列表、字典)不属于常规使用场景,因此其拷贝机制未针对这类场景做特殊处理。如果一定要使用可变对象,需要自行处理深层拷贝的问题。

内容的提问来源于stack exchange,提问作者Tom Kaufman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 23:15:32