pandas.DataFrame.copy(deep=True) 实际上并不创建深层复制

Иль*_*ков 7 python copy list dataframe pandas

我已经用 pd.Series 和 pd.DataFrame 进行了一段时间的实验,并遇到了一些奇怪的问题。假设我有以下 pd.DataFrame:

df = pd.DataFrame({'col':[[1,2,3]]})

请注意,该数据框包括包含列表的列。我想修改此数据框的副本并返回其修改后的版本,以便初始版本保持不变。为了简单起见,假设我想在其单元格中添加整数“4”。

我尝试过以下代码:

def modify(df):
    dfc = df.copy(deep=True)
    dfc['col'].iloc[0].append(4)
    return dfc

modify(df)
print(df)
Run Code Online (Sandbox Code Playgroud)

问题是,除了新的副本之外dfc,初始的 DataFramedf也被修改了。为什么?我应该怎么做才能防止初始数据帧被修改?我的pandas版本是0.25.0

CDJ*_*DJB 6

从这里的文档,在注释部分:

当 deep=True 时,数据会被复制,但实际的 Python 对象不会被递归复制,只会复制对象的引用。这与标准库中的 copy.deepcopy 形成对比,后者递归地复制对象数据(请参见下面的示例)。

这在GitHub 上的本期中再次引用,开发人员声明

在 a 中嵌入可变对象。DataFrame 是一种反模式

所以这个函数正在按照开发人员的预期工作——可变对象(例如列表)不应嵌入到 DataFrame 中。

我找不到copy.deepcopy在 DataFrame 上按预期工作的方法,但我确实使用pickle找到了一个相当糟糕的解决方法:

import pandas as pd
import pickle

df = pd.DataFrame({'col':[[1,2,3]]})

def modify(df):
    dfc = pickle.loads(pickle.dumps(df))
    print(dfc['col'].iloc[0] is df['col'].iloc[0]) #Check if we've succeeded in deepcopying
    dfc['col'].iloc[0].append(4)
    print(dfc)
    return dfc

modify(df)
print(df)
Run Code Online (Sandbox Code Playgroud)

输出:

False
            col
0  [1, 2, 3, 4]
         col
0  [1, 2, 3]
Run Code Online (Sandbox Code Playgroud)