我已经阅读了the docs about slicers一百万次,但我从来没有理解它,所以我仍然在试图弄清楚如何使用loc
切片{ {1}} DataFrame
。
我将从this SO answer开始使用MultiIndex
:
DataFrame
要仅选择 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
和A0
值,我可以这样做:
C1
哪个也适用于三个级别,甚至是元组:
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
到目前为止,直观而精彩。
那为什么我不能从第一个索引级别选择所有值?
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
当然这不是预期的行为吗?
注意:我知道这可以通过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
实现,但当前的df.xs('C1', level='third')
行为似乎不一致。
答案 0 :(得分:15)
这不起作用的原因与指定索引轴的需要有关(在http://pandas.pydata.org/pandas-docs/stable/advanced.html中提到)。解决问题的另一种方法是简单地执行此操作:
df.loc(axis=0)[:, :, 'C1', :]
当索引相似或包含类似值时,Pandas有时会感到困惑。如果你有一个名为&#39; C1&#39;或者你需要在这种切片/选择方式下做这件事。
答案 1 :(得分: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
此处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。