Pandas 数据框的可变性

11

我对Pandas的数据框架很新,如果有人能用以下示例简要讨论DataFrame的可变性,将不胜感激:

d1=pd.date_range('1/1/2016',periods=10,freq='w')
col1=['open','high','low','close']
list1=np.random.rand(10,4)
df1=pd.DataFrame(list1,d1,col1)
据我理解,当前df1是指向一个df对象的引用。
如果我将df1或其切片(例如df1.iloc[2:3,1:2])作为输入传递给一个新的df(例如df2=pd.DataFrame(df1)),那么df2会返回一个新的数据框实例,还是仍然引用df1,使得df1暴露于df2?
此外,任何关于DataFrame可变性需要注意的其他要点都将非常感激。
3个回答

18

这个:

df2 = pd.DataFrame(df1)

构造一个新的DataFrame。有一个copy参数,默认值为False。根据文档,它的意思是:
> Copy data from inputs. Only affects DataFrame / 2d ndarray input

因此,默认情况下会在df2df1之间共享数据。如果您希望没有共享,而是完全复制,请执行以下操作:

因此,默认情况下会在df2df1之间共享数据。如果您希望没有共享,而是完全复制,请执行以下操作:

df2 = pd.DataFrame(df1, copy=True)

更加简洁、地道的说法是:
df2 = df1.copy()

如果你这样做:

df2 = df1.iloc[2:3,1:2].copy()

您将再次获得一个独立的副本。但如果您这样做:

df2 = pd.DataFrame(df1.iloc[2:3,1:2])

它可能会共享数据,但如果您打算修改df,则此样式非常不清晰,因此建议不要编写此类代码。相反,如果您不希望复制,请只说这个:

df2 = df1.iloc[2:3,1:2]

简而言之:如果你想引用现有数据,请不要调用pd.DataFrame()或任何其他方法。如果你想获得一个独立的副本,请调用.copy()


谢谢您的及时回答。看起来,除非我应用复制方法,否则我应该期望从df进行任何切片都是可变的。我的概念正确吗?除了上面提到的切片之外,我意识到像.head() / .tail()这样的操作默认情况下会返回一个新的df实例,它们本身是不可变的。我猜想在这方面.head() / .tail()是不可变的。 - user7786493
作为关于df的可变性的后续问题,以下对df的一部分(其中一列)进行新df的赋值操作是否会创建突变问题?假设df1是一个包含“dummy”列的DataFrame,df2=pd.DataFrame(index=[1,2,3]) 然后执行df2['new dummy']=df1['dummy'] 那么df1的“dummy”列是否会受到影响? - user7786493
@user7786493:不。 - John Zwinck

5

It will probably share the data, but this style is pretty unclear if you intend to modify df, so I suggest not writing such code. Instead, if you want no copy, just say this:

df2 = df1.iloc[2:3,1:2]

In summary: if you want a reference to existing data, do not call > pd.DataFrame() or any other method at all. If you want an independent copy, call .copy()

我不同意。这样做仍然会返回原始DataFrame的切片部分的引用。因此,如果您对df2进行任何更改,它将反映在df1中。

相反,应该使用.copy()方法。

df2 = df1.iloc[2:3,1:2].copy()

作为与切片相关的问题,似乎 df/Series 的索引本身是不可变对象,对 df/Series 对象的索引进行切片操作会返回一个新对象,而不像 df.iloc 的情况那样改变原始对象。例如,在我们的最后一个示例中,df1.index[:] 实际上返回一个新的实例/对象,而不是返回一个引用。我的理解正确吗? - user7786493

2

非常好的问题,谢谢。在阅读其他答案后,我最终进行了一些实验。所以我想与你分享这个。

以下是一些用于实验的代码:

import pandas as pd
import numpy as np
df=pd.DataFrame([[1,2,3],[4,5,6]])
print('start',df,sep='\n',end='\n\n')
def testAddCol(df):
    df=pd.DataFrame(df, copy=True) #experiment in this line: df=df.copy(), df=df.iloc[:2,:2], df.iloc[:2,:2].copy(), nothing, ...
    df['newCol']=11
    df.iloc[0,0]=100
    return df
df2=testAddCol(df)
print('df',df,sep='\n',end='\n\n')
print('df2',df2,sep='\n',end='\n\n')

输出:

start
   0  1  2
0  1  2  3
1  4  5  6

df
   0  1  2
0  1  2  3
1  4  5  6

df2
     0  1  2  newCol
0  100  2  3      11
1    4  5  6      11

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接