pd.DataFrame传入已有DataFrame的行为及相关技术疑问
Pandas浅拷贝与对象引用问题解析
先把你的测试代码贴出来方便对照:
In [1]: import pandas as pd In [2]: a = pd.DataFrame(dict(a=[1,2,3], b=[4,5,6])) In [3]: b = pd.DataFrame(a) In [4]: a['c'] = [7,8,9] In [5]: a Out[5]: a b c 0 1 4 7 1 2 5 8 2 3 6 9 In [6]: b Out[6]: a b c 0 1 4 7 1 2 5 8 2 3 6 9 In [7]: a.drop(columns='c', inplace=True) In [8]: a Out[8]: a b 0 1 4 1 2 5 2 3 6 In [9]: b Out[9]: a b c 0 1 4 7 1 2 5 8 2 3 6 9
问题拆解与解答
1. pd.DataFrame(a)的行为,以及a和b是不是同一对象?
首先明确:a和b是完全不同的DataFrame对象(你已经通过id验证了这一点),但它们在创建初期共享了内部的数据存储,这是Pandas默认的**浅拷贝(shallow copy)**机制导致的:
- 当你用
pd.DataFrame(a)创建b时,Pandas会生成一个新的DataFrame实例(所以id不同),但它不会完全复制a的所有数据,而是复用a的底层数据块和列结构引用。 - 简单说:b是新的"外壳",但里面装的"数据内容"和a共用同一份。这就解释了为什么给a新增列
c时,b也会同步出现这个列——因为你修改的是那份共享的数据内容,两个"外壳"都能看到变化。
2. 为什么删列时b不同步?
a.drop(columns='c', inplace=True)这个操作的本质和加列不一样:
- 加列是直接在共享的数据存储里新增内容,所有引用它的对象都会看到变化;
- 而原地删列操作,并不是直接修改共享的数据存储,而是重新创建了一个不包含
c列的新数据存储,然后替换掉a自己的"数据内容"引用。这时候b的"数据内容"还是原来那份包含c列的旧存储,所以不会跟着删列。
3. 如何让a删列时b同步删除?
如果想要a和b完全同步任何操作,根本不需要创建新对象,直接让b成为a的引用即可:
b = a # 直接赋值,此时a和b指向同一个DataFrame对象
这样不管是加列、删列还是修改单元格数据,a和b的表现都会完全一致,因为它们本质上是同一个对象的两个名字而已。
4. 如何避免加列时b同步新增?
要让a和b彻底独立,互不影响,需要创建深拷贝(deep copy),也就是完全复制a的所有数据和结构,生成一个完全独立的新对象:
# 两种写法都可以 b = pd.DataFrame(a, copy=True) # 或者更直观的 b = a.copy(deep=True)
之后不管a做任何修改(加列、删列、改数据),b都不会受到任何影响,因为它有自己独立的数据存储了。
内容的提问来源于stack exchange,提问作者JNL
相关产品推荐
相关产品推荐

