Python:Pandas对象的深浅拷贝

这里仅以DataFrame为例进行说明。
Pandas版本:1.5.3

1 问题描述

  现有一DataFrame型变量A,现在需要对变量A做一些处理操作,但又希望保存A的一个原始副本。所以考虑将变量A赋值给变量B,然后再变量B上进行处理操作。但是处理完却发现A中的值也跟着发生了变动。具体举例如下:
在这里插入图片描述很显然,上述代码中虽然没有直接对A进行变换,但A的值还是发生了变化。这就涉及到了Python的深浅拷贝问题。本文主要关注Pandas对象的深浅拷贝,其他类型变量的深浅拷贝可以参考:https://blog.csdn.net/yeshang_lady/article/details/80755061

2 Pandas对象深浅拷贝

  Pandas中提供了copy()方法来对其对象进行拷贝,其内设的bool型参数deep可以设置是进行深拷贝。另外,copy标准库中deepcopy()方法也可以完成Pandas对象的深拷贝。这三者的区别如下:

  • deep=False:只对Pandas对象的数据和元素进行浅拷贝,即只复制数据和索引的引用,对副本变量的修改会影响原始数据。
  • deep=True:会对数据和索引进行复制。在副本变量上的修改不会影响原始变量。但这种复制不能递归(即当Pandas中的数据也是一个引用时,该方法不会对该引用的具体内容也进行复制)。
  • copy.deepcopy: 会对数据和索引进行复制,并且这种复制是可递归的。

2.1 对索引/列名的修改

  先创建对象A,并使用不同拷贝方法创建A的副本对象。先用id()方法来查看各个副本对象的列名/索引信息存放的位置是否相同。具体代码如下:

import pandas as pd
from copy import deepcopy
A=pd.DataFrame([['A',[3000,3002],22],
                ['B',[3010,2900],29]],columns=['col_1','col_2','col_3'])
A_deep=A.copy(deep=True)
A_shallow=A.copy(deep=False)
A_copy=deepcopy(A)

#查看各个对象的索引和列名的存放地址
print("对象A的索引存放地址:{},列名存放地址:{}".format(id(A.index),id(A.columns)))
print("对象A_deep的索引存放地址:{},列名存放地址:{}".format(id(A_deep.index),id(A_deep.columns)))
print("对象A_shallow的索引存放地址:{},列名存放地址:{}".format(id(A_shallow.index),id(A_shallow.columns)))
print("对象A_copy的索引存放地址:{},列名存放地址:{}".format(id(A_copy.index),id(A_copy.columns)))

其结果如下:
在这里插入图片描述
从图上可以看出,浅拷贝得到的对象A_shallow的索引和列名存放地址与原始变量A的存放地址相同。而其他两种方法得到的存放地址与原始变量A不同。但由于DataFrame型变量的索引和列名都是不可变对象,所以对A_shallow中的列名或索引的修改不会导致原始变量A的改变。具体如下:

#A_shallow.columns[0]='A1' 无法运行,提示其为不可变类型
A_shallow.columns=['A1','B1','C1'] #这种写法相当于将A_shallow的列名指向内存中另外一个地址
print("修改后的A_shallow的列名:",list(A_shallow.columns))
print("修改A_shallow的列名后A的列名:",list(A.columns))
print("修改后的A_shallow的列名存放地址:",id(A_shallow.columns))

其结果如下:
在这里插入图片描述
从图中可以看到,A_shallow的列名改名并没有导致A跟着变动。(修改索引也是)

2.2 数据修改

  • 第1种情况:浅拷贝(deep=False)。具体如下:
import pandas as pd
from copy import deepcopy
A=pd.DataFrame([['A',[3000,3002],22],
                ['B',[3010,2900],29]],columns=['col_1','col_2','col_3'])
A_shallow=A.copy(deep=False)
A_shallow.loc[0,'col_1']='C'
A_shallow['col_3']=[34,27]

A_shallow和A的值如下:
在这里插入图片描述
从结果上可以看到奇怪的现象,就是对A_shallow中col_3整列的修改并没有影响到A中的相应列,好似与浅拷贝的定义不符合。这是因为A_shallow中的col_3指向了新的内存地址,而A中col_3列指向的位置不变。这与下述代码同义:

a=[1,2]
print(a,id(a))
a[0]=0
print(a,id(a))
a=[2,3,5]
print(a,id(a))

其结果如下:
在这里插入图片描述

  • 第2种情况:深拷贝(deep=True)。具体如下:
import pandas as pd
from copy import deepcopy
A=pd.DataFrame([['A',[3000,3002],4002],
                ['B',[3010,2900],3009]],columns=['col_1','col_2','col_3'])
A_deep=A.copy(deep=True)
A_deep.loc[0,'col_1']='C'
A_deep.loc[0,'col_2'][0]=3
A_deep.loc[1,'col_2']=[2020]

其结果如下:
在这里插入图片描述

  • 第3种情况:deepcopy()方法。具体如下:
import pandas as pd
from copy import deepcopy
A=pd.DataFrame([['A',[3000,3002],4002],
                ['B',[3010,2900],3009]],columns=['col_1','col_2','col_3'])
A_copy=deepcopy(A)
A_copy['col_2']=[[2002,2012],[3030,2020]]
A_copy.loc[0,'col_1']='E'

其结果如下:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/yeshang_lady/article/details/129582248
今日推荐