pandas dataframe view vs copy,我怎么说?

use*_*451 14 python pandas

有什么区别:

大熊猫 df.loc[:,('col_a','col_b')]

df.loc[:,['col_a','col_b']]

下面的链接没有提到后者,虽然它有效.拉两个视图?首先是拉视图而第二个是拉副本吗?喜欢学习熊猫.

http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

谢谢

unu*_*tbu 25

如果您的DataFrame有一个简单的列索引,那么没有区别.例如,

In [8]: df = pd.DataFrame(np.arange(12).reshape(4,3), columns=list('ABC'))

In [9]: df.loc[:, ['A','B']]
Out[9]: 
   A   B
0  0   1
1  3   4
2  6   7
3  9  10

In [10]: df.loc[:, ('A','B')]
Out[10]: 
   A   B
0  0   1
1  3   4
2  6   7
3  9  10
Run Code Online (Sandbox Code Playgroud)

但是如果DataFrame有一个MultiIndex,那么可能会有很大的不同:

df = pd.DataFrame(np.random.randint(10, size=(5,4)),
                  columns=pd.MultiIndex.from_arrays([['foo']*2+['bar']*2,
                                                     list('ABAB')]),
                  index=pd.MultiIndex.from_arrays([['baz']*2+['qux']*3,
                                                   list('CDCDC')]))

#       foo    bar   
#         A  B   A  B
# baz C   7  9   9  9
#     D   7  5   5  4
# qux C   5  0   5  1
#     D   1  7   7  4
#     C   6  4   3  5

In [27]: df.loc[:, ('foo','B')]
Out[27]: 
baz  C    9
     D    5
qux  C    0
     D    7
     C    4
Name: (foo, B), dtype: int64

In [28]: df.loc[:, ['foo','B']]
KeyError: 'MultiIndex Slicing requires the index to be fully lexsorted tuple len (1), lexsort depth (0)'
Run Code Online (Sandbox Code Playgroud)

KeyError表示MultiIndex必须是lexsorted.如果我们这样做,那么我们仍会得到不同的结果:

In [29]: df.sortlevel(axis=1).loc[:, ('foo','B')]
Out[29]: 
baz  C    9
     D    5
qux  C    0
     D    7
     C    4
Name: (foo, B), dtype: int64

In [30]: df.sortlevel(axis=1).loc[:, ['foo','B']]
Out[30]: 
      foo   
        A  B
baz C   7  9
    D   7  5
qux C   5  0
    D   1  7
    C   6  4
Run Code Online (Sandbox Code Playgroud)

这是为什么?df.sortlevel(axis=1).loc[:, ('foo','B')]正在选择第一列级别等于的列foo,第二列级别是B.

相反,df.sortlevel(axis=1).loc[:, ['foo','B']]选择第一列级别为foo或的列B.关于第一列级别,没有B列,但有两foo列.

我认为Pandas的操作原理是如果你df.loc[...]用作表达式,你应该假设df.loc可能正在返回一个副本或一个视图.Pandas文档没有指定您应该期望的任何规则.但是,如果您对表单进行了分配

df.loc[...] = value
Run Code Online (Sandbox Code Playgroud)

那么你可以信任熊猫改变df自己.

文档警告视图和副本之间区别的原因是您了解使用表单链分配的缺陷

df.loc[...][...] = value
Run Code Online (Sandbox Code Playgroud)

在这里,Pandas df.loc[...]首先评估,可能是视图或副本.现在,如果它是副本,那么

df.loc[...][...] = value
Run Code Online (Sandbox Code Playgroud)

正在改变某些部分的副本df,因此对df自身没有影响.为了增加对伤害的侮辱,对副本的影响也会丢失,因为没有对副本的引用,因此在赋值语句完成后无法访问副本,并且(至少在CPython中)它很快就会出现被垃圾收集.


我不知道一种实用的万无一失的先验方法来确定是否df.loc[...]要返回视图或副本.

但是,有一些经验法则可能有助于指导您的直觉(但请注意,我们在这里讨论实现细节,因此无法保证Pandas将来需要以这种方式行事):

  • 如果生成的NDFrame不能表示为底层NumPy数组的基本切片,那么它可能是一个副本.因此,选择任意行或列将导致复制.选择的顺序行和/或顺序列(可以表示为切片)可以返回视图.
  • 如果生成的NDFrame具有不同dtypes的列,则df.loc 可能再次返回副本.

但是,有一种简单的方法可以确定x = df.loc[..]视图是否为postiori:只需查看是否更改了值的x影响df.如果是,则视图(如果不是)x是副本.

  • 当用作表达式时,`df.loc [...]`调用`df.loc .__ getitem __(...)`.当用作赋值时,`df.loc [...] = value`调用`df.loc .__ setitem __(...,value)`.`__getitem__`方法可以返回视图或副本.但是`__setitem__`方法总是会修改`df`本身.毕竟,这是`__setitem__`唯一合理的事情. (4认同)
  • 如果我们只是使用像 `df.loc[..]` 这样的表达式并且结果是一个副本,那么为什么像 `df.loc[..] = ...` 这样的东西会以某种方式变成一个视图?好像有点腥 但是非常感谢你的解释。现在感觉比较清楚了。 (2认同)