使用复合(分层)索引从Pandas数据框中选择行

时间:2012-08-13 20:07:07

标签: python pandas dataframe multi-index

我怀疑这是微不足道的,但我还没有发现让我根据分层键的值从Pandas数据帧中选择行的咒语。因此,例如,假设我们有以下数据框:

import pandas
df = pandas.DataFrame({'group1': ['a','a','a','b','b','b'],
                       'group2': ['c','c','d','d','d','e'],
                       'value1': [1.1,2,3,4,5,6],
                       'value2': [7.1,8,9,10,11,12]
})
df = df.set_index(['group1', 'group2'])

df看起来像我们期望的那样:

enter image description here

如果df未在group1上编入索引,我可以执行以下操作:

df['group1' == 'a']

但是这个带有索引的数据帧失败了。所以也许我应该把它想象成一个带有分层索引的Pandas系列:

df['a','c']

不。那也失败了。

那么如何选择所有行:

  1. group1 =='a'
  2. group1 =='a'& group2 =='c'
  3. group2 =='c'
  4. ['a','b','c']中的group1

3 个答案:

答案 0 :(得分:49)

尝试使用xs非常精确:

In [5]: df.xs('a', level=0)
Out[5]: 
        value1  value2
group2                
c          1.1     7.1
c          2.0     8.0
d          3.0     9.0

In [6]: df.xs('c', level='group2')
Out[6]: 
        value1  value2
group1                
a          1.1     7.1
a          2.0     8.0

答案 1 :(得分:9)

以下语法将起作用:

df.ix['a']
df.ix['a'].ix['c']

因为group1group2是索引。请原谅我以前的尝试!

要获得第二个索引,我认为你必须交换索引:

df.swaplevel(0,1).ix['c']

但我确信如果我错了,Wes会纠正我。

答案 2 :(得分:1)

在Python 0.19.0中有一种新的建议方法,在此处解释1。我相信他们给出的最明显的例子如下,他们从四级索引切片。这就是数据帧的制作方式:

In [46]: def mklbl(prefix,n):
   ....:     return ["%s%s" % (prefix,i)  for i in range(n)]
   ....: 

In [47]: miindex = pd.MultiIndex.from_product([mklbl('A',4),
   ....:                                       mklbl('B',2),
   ....:                                       mklbl('C',4),
   ....:                                       mklbl('D',2)])
   ....: 

In [48]: micolumns = pd.MultiIndex.from_tuples([('a','foo'),('a','bar'),
   ....:                                        ('b','foo'),('b','bah')],
   ....:                                       names=['lvl0', 'lvl1'])
   ....: 

In [49]: dfmi = pd.DataFrame(np.arange(len(miindex)*len(micolumns)).reshape((len(miindex),len(micolumns))),
   ....:                     index=miindex,
   ....:                     columns=micolumns).sort_index().sort_index(axis=1)
   ....: 

In [50]: dfmi
Out[50]: 
lvl0           a         b     
lvl1         bar  foo  bah  foo
A0 B0 C0 D0    1    0    3    2
         D1    5    4    7    6
      C1 D0    9    8   11   10
         D1   13   12   15   14
      C2 D0   17   16   19   18
         D1   21   20   23   22
      C3 D0   25   24   27   26
...          ...  ...  ...  ...
A3 B1 C0 D1  229  228  231  230
      C1 D0  233  232  235  234
         D1  237  236  239  238
      C2 D0  241  240  243  242
         D1  245  244  247  246
      C3 D0  249  248  251  250
         D1  253  252  255  254

这就是他们选择不同行的方式:

In [51]: dfmi.loc[(slice('A1','A3'),slice(None), ['C1','C3']),:]
Out[51]: 
lvl0           a         b     
lvl1         bar  foo  bah  foo
A1 B0 C1 D0   73   72   75   74
         D1   77   76   79   78
      C3 D0   89   88   91   90
         D1   93   92   95   94
   B1 C1 D0  105  104  107  106
         D1  109  108  111  110
      C3 D0  121  120  123  122
...          ...  ...  ...  ...
A3 B0 C1 D1  205  204  207  206
      C3 D0  217  216  219  218
         D1  221  220  223  222
   B1 C1 D0  233  232  235  234
         D1  237  236  239  238
      C3 D0  249  248  251  250
         D1  253  252  255  254

非常简单,在df.loc[(indices),:]中,您可以指定要从每个级别选择的索引,从最高级别到最低级别。如果您不想选择最低级别的索引,则可以省略指定它们。如果您不想在其他指定级别之间进行切片,则添加slice(None)。这两种情况都显示在示例中,其中省略了级别D,并且在A和C之间指定了级别B.