dataframe和list的深浅拷贝以及dataframe中存储list或list中存储dataframe时的深浅拷贝误区

本文讲述下python中dataframe和list的深浅拷贝以及dataframe中存储list或list中存储dataframe时的深浅拷贝误区。dataframe和list的深浅拷贝其实网上资料都有很多了,这个也容易搞懂,但是当dataframe中存储着list时,或list中存储着dataframe时,要注意此时即使进行了深拷贝,也不一定是你所想像的深拷贝。比如dataframe中存储着list时,对dataframe进行了深拷贝,修改list中的元素时,原来的dataframe中的list中的元素也会发生改变,因为本质上深拷贝对datyaframe而言却是是深拷贝,但是此时dataframe中的元素是list的引用,这个并没有进行深拷贝。详细说明还是用代码来进行把,文字解释终归不清楚。(要想完全透彻理解最好学下c语言的指针就可以了)

import copy 
import pandas as pd

1.list的深拷贝与浅拷贝

x = [1,2,3,4,5]
y=x
print(y)
[1, 2, 3, 4, 5]
y[2]=999
x
[1, 2, 999, 4, 5]

因此y=x的方式对于list来说,是做了一个引用,并没有真的拷贝list。

x = [1,2,3,4,5]
y=copy.copy(x)
print(y)
[1, 2, 3, 4, 5]
y[2]=999
x
[1, 2, 3, 4, 5]

因此y=copy.copy(x)的方式对于list来说,是真的做了拷贝。

x = [[1,2],
     [3,4],
     [5,6]]
y=copy.copy(x)
print(y)
[[1, 2], [3, 4], [5, 6]]
y[1][1]=9999
x
[[1, 2], [3, 9999], [5, 6]]
y[0][0]=9999
x
[[9999, 2], [3, 9999], [5, 6]]

因此y=copy.copy(x)的方式对于二维list来说,并没有真正做拷贝,只是做了引用。

x = [[1,2],
     [3,4],
     [5,6]]
y=copy.deepcopy(x)
print(y)
[[1, 2], [3, 4], [5, 6]]
y[1][1]=9999
x
[[1, 2], [3, 4], [5, 6]]

因此y=copy.deepcopy(x)的方式对于二维list来说,是真的做了拷贝。

2.series和dataframe的深拷贝与浅拷贝

df1 = pd.DataFrame([[1,2,3],[6,7,8]])
df2=df1
df2
0 1 2
0 1 2 3
1 6 7 8
df2[2]=999
df1
0 1 2
0 1 2 999
1 6 7 999

因此df2=df1的方式对于dataframe来说并没有真正做拷贝,只是做了引用。

df1 = pd.DataFrame([[1,2,3],[6,7,8]])
df2=copy.deepcopy(df1)
df2
0 1 2
0 1 2 3
1 6 7 8
df2[2]=999
df1
0 1 2
0 1 2 3
1 6 7 8

因此df2=copy.deepcopy(df1)的方式对于dataframe来说做了真正的拷贝。

s1 = pd.Series([1, 2, 3, 4])
s2=copy.deepcopy(s1)
s2
0    1
1    2
2    3
3    4
dtype: int64
s2[1]=999
s1
0    1
1    2
2    3
3    4
dtype: int64

series与dataframe一样。

s1 = pd.Series([1, 2, 3, 4])
s2=s1.copy()
s2
0    1
1    2
2    3
3    4
dtype: int64
del s2[1]
s1
0    1
1    2
2    3
3    4
dtype: int64
s1 = pd.Series([1, 2, 3, 4])
s2=s1.copy(deep=True)
s2
0    1
1    2
2    3
3    4
dtype: int64
del s2[1]
s1
0    1
1    2
2    3
3    4
dtype: int64

3. dataframe中有list时的深拷贝误区

df1 = pd.DataFrame({'A':[[1,2],[3,4],[5,6]],'B':[[7,8],[9,10],[11,12]]})
df1
A B
0 [1, 2] [7, 8]
1 [3, 4] [9, 10]
2 [5, 6] [11, 12]
df2=df1.copy(deep=True)
df3=copy.deepcopy(df1)
df2
A B
0 [1, 2] [7, 8]
1 [3, 4] [9, 10]
2 [5, 6] [11, 12]
# 现在对df2和df3中的list中的元素做修改
df2.iloc[0,0][0]=999
df3.iloc[1,0][0]=999
df2
A B
0 [999, 2] [7, 8]
1 [999, 4] [9, 10]
2 [5, 6] [11, 12]
df3
A B
0 [999, 2] [7, 8]
1 [999, 4] [9, 10]
2 [5, 6] [11, 12]
df1
A B
0 [999, 2] [7, 8]
1 [999, 4] [9, 10]
2 [5, 6] [11, 12]

可见我明明是对df1进行了深拷贝,可是当我改变深拷贝过来的df2和df3的list中的元素时,df1也会跟着改变,这是为什么呢?

因为我仅仅对dataframe进行了深拷贝,因此我得到了一个新的dataframe,该dataframe和原来的dataframe一样,每个元素存储的都是list的引用,注意是list的引用而不是list,因此我实际上是深拷贝了list的引用,但是并不是把里面的数据都拷贝了一遍,当我修改深拷贝过来的dataframe中的list中的元素时,我是真正的改掉了list中的元素,因此原来的dataframe和深拷贝的dataframe中的每个元素的引用中的元素都被改掉了,这就是出现上述现象的原因。

上一篇:萌新初学java,自己写的剧本,求大佬帮忙纠正下语法上的错误,能让内容更完善些代码量更少些


下一篇:学习 Java 编程语言:for 确定循环语句