本文讲述下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中的每个元素的引用中的元素都被改掉了,这就是出现上述现象的原因。