为什么使用 Pandas 多级索引数据框切片似乎不一致?

3
为什么在切分多级索引的数据框时,只要切分第0级索引,你就可以使用更简单的语法?以下是一个示例数据框:
           hi
a b   c      
1 foo baz   0
      can   1
  bar baz   2
      can   3
2 foo baz   4
      can   5
  bar baz   6
      can   7
3 foo baz   8
      can   9
  bar baz  10
      can  11

以下内容是有效的:

df.loc[1, 'foo', :]
df.loc[1, :, 'can']

虽然这并不会:
df.loc[:, 'foo', 'can']

强制我使用其中之一:
df.loc[(slice(None), 'foo', 'can'), :]
df.loc[pd.IndexSlice[:, 'foo', 'can'], :]

以下是同样的例子,但加入了更多细节:
In [1]: import pandas as pd
import numpy as np

ix = pd.MultiIndex.from_product([[1, 2, 3], ['foo', 'bar'], ['baz', 'can']], names=['a', 'b', 'c'])
data = np.arange(len(ix))
df = pd.DataFrame(data, index=ix, columns=['hi'])
print df

           hi
a b   c      
1 foo baz   0
      can   1
  bar baz   2
      can   3
2 foo baz   4
      can   5
  bar baz   6
      can   7
3 foo baz   8
      can   9
  bar baz  10
      can  11

In [2]: df.sort_index(inplace=True)
print df.loc[1, 'foo', :]

           hi
a b   c      
1 foo baz   0
      can   1

In [3]: print df.loc[1, :, 'can']

           hi
a b   c      
1 bar can   3
  foo can   1

In [4]: print df.loc[:, 'foo', 'can']

KeyError: 'the label [foo] is not in the [columns]'

In [5]: print df.loc[(slice(None), 'foo', 'can'), :]

           hi
a b   c      
1 foo can   1
2 foo can   5
3 foo can   9

In [6]: print df.loc[pd.IndexSlice[:, 'foo', 'can'], :]

           hi
a b   c      
1 foo can   1
2 foo can   5
3 foo can   9
1个回答

3

这三个例子在技术上是有歧义的,但在前两个例子中,Pandas能够正确地猜测你的意图。由于对行进行切片、选择列(即 df.loc[:, columns])是一种常见的惯用语,推断似乎选择了这种解释。

推断有点混乱,所以我认为更好的做法是明确表达。如果给IndexSlice设置别名,增加的输入量也不多:

idx = pd.IndexSlice
df.loc[idx[1, 'foo'], :]
df.loc[idx[1, :, 'can'], :]
df.loc[idx[:, 'foo', 'can'], :]

1
为什么 df.loc[:, columns] 是一个常见的习惯用语,而 df[columns] 看起来似乎可以做同样的事情?我可能错过了一些微妙之处。 - MarredCheese
通常情况下它会做相同的事情...除非由于回退而不这样做。在github上有一个问题列出了所有可能性 - https://github.com/pydata/pandas/issues/9595 - 如上所述,这有点混乱,目前主要是为了向后兼容。 - chrisb

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