使用DataFrame.loc"太多索引器"

Lon*_*Rob 23 python pandas

我已经阅读了有关切片器一百万次的文档,但是我从来没有理解它,所以我仍然试图弄清楚如何使用loc切片DataFramea MultiIndex.

DataFrame将从这个SO答案开始:

                           value
first second third fourth       
A0    B0     C1    D0          2
                   D1          3
             C2    D0          6
                   D1          7
      B1     C1    D0         10
                   D1         11
             C2    D0         14
                   D1         15
A1    B0     C1    D0         18
                   D1         19
             C2    D0         22
                   D1         23
      B1     C1    D0         26
                   D1         27
             C2    D0         30
                   D1         31
A2    B0     C1    D0         34
                   D1         35
             C2    D0         38
                   D1         39
      B1     C1    D0         42
                   D1         43
             C2    D0         46
                   D1         47
A3    B0     C1    D0         50
                   D1         51
             C2    D0         54
                   D1         55
      B1     C1    D0         58
                   D1         59
             C2    D0         62
                   D1         63
Run Code Online (Sandbox Code Playgroud)

要选择公正A0C1价值观,我可以这样做:

In [26]: df.loc['A0', :, 'C1', :]
Out[26]: 
                           value
first second third fourth       
A0    B0     C1    D0          2
                   D1          3
      B1     C1    D0         10
                   D1         11
Run Code Online (Sandbox Code Playgroud)

哪个也适用于三个级别,甚至是元组:

In [28]: df.loc['A0', :, ('C1', 'C2'), 'D1']
Out[28]: 
                           value
first second third fourth       
A0    B0     C1    D1          3
             C2    D1          5
      B1     C1    D1         11
             C2    D1         13
Run Code Online (Sandbox Code Playgroud)

到目前为止,直观而精彩.

那么为什么我不能从第一个索引级别选择所有值呢?

In [30]: df.loc[:, :, 'C1', :]
---------------------------------------------------------------------------
IndexingError                             Traceback (most recent call last)
<ipython-input-30-57b56108d941> in <module>()
----> 1 df.loc[:, :, 'C1', :]

/usr/local/lib/python2.7/dist-packages/pandas/core/indexing.pyc in __getitem__(self, key)
   1176     def __getitem__(self, key):
   1177         if type(key) is tuple:
-> 1178             return self._getitem_tuple(key)
   1179         else:
   1180             return self._getitem_axis(key, axis=0)

/usr/local/lib/python2.7/dist-packages/pandas/core/indexing.pyc in _getitem_tuple(self, tup)
    694 
    695         # no multi-index, so validate all of the indexers
--> 696         self._has_valid_tuple(tup)
    697 
    698         # ugly hack for GH #836

/usr/local/lib/python2.7/dist-packages/pandas/core/indexing.pyc in _has_valid_tuple(self, key)
    125         for i, k in enumerate(key):
    126             if i >= self.obj.ndim:
--> 127                 raise IndexingError('Too many indexers')
    128             if not self._has_valid_type(k, i):
    129                 raise ValueError("Location based indexing can only have [%s] "

IndexingError: Too many indexers
Run Code Online (Sandbox Code Playgroud)

当然这不是预期的行为吗?

注意:我知道这是可能的,df.xs('C1', level='third')但目前的.loc行为似乎不一致.

dja*_*sky 16

这不起作用的原因与指定索引轴的需要有关(在http://pandas.pydata.org/pandas-docs/stable/advanced.html中提到).解决问题的另一种方法是简单地执行此操作:

df.loc(axis=0)[:, :, 'C1', :]
Run Code Online (Sandbox Code Playgroud)

当索引相似或包含类似的值时,Pandas有时会感到困惑.如果你有一个名为'C1'的列,或者你需要在这种切片/选择方式下做这个.


jor*_*ris 13

为了安全(在某种意义上:这将适用于所有情况),您需要索引行索引和列,您可以使用pd.IndexSlice它们轻松地执行此操作:

In [26]: idx = pd.IndexSlice

In [27]: df.loc[idx[:, :, 'C1', :],:]
Out[27]:
                           value
first second third fourth
A0    B0     C1    D0          2
                   D1          3
      B1     C1    D0         10
                   D1         11
A1    B0     C1    D0         18
                   D1         19
      B1     C1    D0         26
                   D1         27
A2    B0     C1    D0         34
                   D1         35
      B1     C1    D0         42
                   D1         43
A3    B0     C1    D0         50
                   D1         51
      B1     C1    D0         58
                   D1         59
Run Code Online (Sandbox Code Playgroud)

idx[:, :, 'C1', :]是一种更简单的写作方式[slice(None), slice(None),'C1', slice(None)].而不是pd.IndexSlice,你也可以使用np.s_更短的.

其他工作的原因,我不完全确定.但请参阅此处文档中的说明:http://pandas.pydata.org/pandas-docs/stable/advanced.html#using-slicers(第一个红色警告框),其中声明:

您应该在说明.loc符中指定所有轴,这意味着索引和列的索引器.它们是一些模糊的情况,传递的索引器可能被错误解释为索引两个轴,而不是行的MuliIndex.

  • 这是我第一次真正理解文档部分的内容。 (2认同)