带有“_is_view=True”的 pandas 数据帧切片不会更改原始数据帧,而“_is_view”保持为 True

pandas dataframe slice with '_is_view=True' doesn't change original dataframe and '_is_view' stays True

提问人:Franco Ferrucci 提问时间:7/2/2023 最后编辑:Franco Ferrucci 更新时间:7/2/2023 访问量:43

问:

你能不能向我解释为什么我从这段代码中得到以下结果:

import pandas as pd
df1 = pd.DataFrame([[1, 0.3, 1.3],[4, 6, 5.2],[43, 6.8, 55.2]])
df2 = df1.loc[1,0:] # 2nd row, all columns
print(df2._is_view) # True
print(df2._is_copy) # None
df2.iloc[1] = 999 # It changes df2 without warnings but df1 stays unchanged
print(df2._is_view) # Still True

据我了解,这条线也应该改变。df2.iloc[1] = 999df1

请注意,如果我选择第二列,所有行(而不是第二行,所有列),代码将按“预期”工作(即 df1 被修改):

import pandas as pd
df1 = pd.DataFrame([[1, 0.3, 1.3],[4, 6, 5.2],[43, 6.8, 55.2]])
df2 = df1.loc[0:,1] # 2nd column, all rows.
print(df2._is_view) # True
print(df2._is_copy) # None
df2.iloc[1] = 999   # It DOES changes df1 as well ! 
print(df2._is_view) # Still True

谢谢大家!

我尝试了上面的代码,但我仍然无法理解发生了什么。 (Pandas 版本:“2.0.2”,Python 版本 3.11.4)

Pandas 数据帧 切片

评论


答:

1赞 Ziur Olpa 7/2/2023 #1

据我所知,我可能是错的,pandas DataFrame 是一个对象,它是 pandas 系列的集合,pandas 系列被定义为一列而不是一行。

如果不检查 pandas 的内部结构,就很难知道,但我可以想象的是,提取一行将在内存中分配一个新对象,而提取一列将重用存在于 dataFrame 中的现有 Series。

您可以检查此语句运行几次:

id(df1[1])  # no new id is generated, is just the internal Series

有趣的是,当您运行时,情况并非如此:

id(df1.loc[0:,1])
id(df1.loc[1,0:]) 

由于使用此表示法是在内存中分配一个新地址,可能是因为考虑到您正在对 Series 进行迭代,并且在行情况下,因为没有包含该行的对象,因此它需要迭代。

所以对我来说,在序列的 setter 中有一些我们没有看到的内部检查,这确保了当你修改序列时它会改变,但当你改变你刚刚通过迭代一行创建的随机序列时,它不会。

无论如何,以通常的方式调用列时,一切都会更加自然,所以我想这可能不是使用 loc 的情况的最终答案。

无论如何,请记住,“_is_view”和“_is_copy”不属于 pandas 的公共 API(它们是内部实现,就像任何以 _ 开头的东西一样),并且不打算供最终用户使用。(它们可能具有误导性)