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
python
list
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