Python 为什么分配给数据帧转置时会丢失数据?
假设我有一个像Python 为什么分配给数据帧转置时会丢失数据?,python,pandas,dataframe,transpose,Python,Pandas,Dataframe,Transpose,假设我有一个像 df = pd.DataFrame({'A':[1,2,3,4],'B':[1,3,4,7]}) 运行此操作后,数据帧中没有任何更改 但问题是数据存储在哪里?为什么它没有给出任何错误?我希望这种赋值或类似的输出出现错误 A B 0 1 1 1 2 3 2 3 4 3 4 7 C 3 3 df.T是另一个对象。您所做的更改不会反映在原始df中。它在哪里?因为没有指向它的变量,所以它要么已经被垃圾收集器收集,要么正在等待被收集。您无法访问它 您可以做的是创建一
df = pd.DataFrame({'A':[1,2,3,4],'B':[1,3,4,7]})
运行此操作后,数据帧中没有任何更改
但问题是数据存储在哪里?为什么它没有给出任何错误?我希望这种赋值或类似的输出出现错误
A B
0 1 1
1 2 3
2 3 4
3 4 7
C 3 3
df.T
是另一个对象。您所做的更改不会反映在原始df中。它在哪里?因为没有指向它的变量,所以它要么已经被垃圾收集器收集,要么正在等待被收集。您无法访问它
您可以做的是创建一个新变量
transposed = df.T
transposed['C'] = 3
transposed
Out:
0 1 2 3 C
A 1 2 3 4 3
B 1 3 4 7 3
当您调用任何返回新数据帧的方法时,也会发生同样的情况df.drop(0)['C']=2
,df.reset_index()['C']=3
或df.drop_duplicates()['C']=3
。原始数据帧始终保持不变。有另一个数据帧是用指定给它的确切行创建的,但是一旦执行该语句,它就变得不可访问,因为没有任何变量指向它。对于CPython的垃圾收集,有一些有用的信息
从@Bharath编辑: (我的一位老师的解释)
T返回一个副本
。这意味着分配了新内存来存储新对象。如果您查找python垃圾收集,您会发现内存中的每个对象都有一个计数器,指示有多少指针指向它
当垃圾收集运行时,它会在内存中找到这个对象,并看到它有零指针。因为它有零指针,垃圾收集将回收内存,对象将永远消失
因此,建议通过指定名称(或变量)来保持单个指针指向对象。方法
T
返回super(DataFrame,self)。transpose(1,0,**kwargs)它将创建另一个数据帧。除了现有的答案之外,我想提请您注意-
df
A B
0 1 1
1 2 3
2 3 4
3 4 7
df.T['C'] = 3
df
A B
0 1 1
1 2 3
2 3 4
3 4 7
pythonlist
s的类似情况-
l = [1, 2, 3, 4, 5]
l[:].append(6)
l
[1, 2, 3, 4, 5]
在这两种情况下都会创建一个新对象!然后将该操作应用于新创建的对象,随后该对象将被垃圾收集,因为没有指向它的活动引用。你看到这个了吗-
import sys
sys.getrefcount(df.T)
1
该对象只有一个引用(该时间点的引用,随后丢失)。一旦你接受了df.T
返回一个全新的对象这一事实,这就变得很容易理解了(我已经说过了,但我正试图阐明这一点)-
总之,您正在尝试修改一个没有引用的新对象,并且您没有看到对原始对象的任何更改,因为您没有进行任何更改。df.T['C']=3的预期结果是什么?请改用
df.T.assign(C=3)
?我可以知道为什么吗?这真的是一个愚蠢的问题吗?@Zero先生是的,我很想知道为什么数据会丢失。也许正如Ayhan所说,这是因为没有变量指向它。只是问一下,它是df=df.T['C']=3
还是df.T['C']=3
?下面的答案谈到了这一点。我知道复制,但垃圾收集器对我来说是新的。我很好奇它为什么丢了。为什么没有显示任何错误。我们应该向熊猫报告吗?@Bharath从某种意义上说,这就像是链式作业,但这可能并不常见。如果您执行df.drop(0)['C']=2
,它也不会发出任何警告(它也不会修改df)。由于您正在动态地执行这些操作,而没有将其分配给变量,因此它甚至可能没有机会发出警告。至于垃圾收集,可能会有帮助。对于引用计数,您不仅要考虑创建的引用;熊猫创造的东西也很重要,有些未知(你需要挖得深一点)。@Bharath不,当然不是。Python处理变量/名称的方式与许多语言不同,大多数人都在为这些引用而挣扎。我不会对落选的选票读太多。可能有数百万个原因。它们可能合乎逻辑,也可能不合逻辑。除非投票者自己解释,否则我不会在意。@ElisByberi所以如果我想计算一个合计数,我应该继续修改原始数据框?那肯定会打乱我的工作流程。我的一半代码将包含copy()
s.@ElisByberi我认为我们是在循环运行。:)为什么要编写filter(groupby(reset_index)(set_index)(drop(rename(df,arg),arg),arg),arg)
而您可以编写df.rename(arg).drop(arg).set_index(arg).reset_index(arg).groupby(arg).filter(arg)
。这是不直观的(您正在以相反的顺序调用函数),并且很难读取/跟踪。@Bharath这不是一个解释,而是一个提示:DataFrame
的父类中的方法transpose
执行此操作,而返回self.\u构造函数(新值,**新轴)。\u\u finalize\u(self)
这是一种就地转置。@Bharath这是pandas关于方法T()
:DataFrame.T、转置索引和列的文档。这太荒谬了!哈哈哈!一段代码和一个片段来解释发生了什么总是一个很棒的答案。感谢You@Bharath事实上,根本没有对新创建的对象的引用。垃圾收集器不应该因为您“丢失”了对象而受到责备。我将自己提出一个问题并给出答案(也欢迎其他同事的回答)。我真的厌倦了一遍又一遍地向任何人解释这件事。我的那个问题对每个人来说都是一个很好的参考。当它准备好时,我会ping你。@ElisByberi事实是,根本没有对新创建的对象的引用。这是阿扬在回答中所说的,也是我老师所说的。我很好奇什么
df
A B
0 1 1
1 2 3
2 3 4
3 4 7
df.T['C'] = 3
df
A B
0 1 1
1 2 3
2 3 4
3 4 7
l = [1, 2, 3, 4, 5]
l[:].append(6)
l
[1, 2, 3, 4, 5]
import sys
sys.getrefcount(df.T)
1
id(df.T)
4612098928
id(df.T)
4612098872
id(df.T)
4612098592