从具有复合(分层)索引的 Pandas 数据框中选择行

Posted

技术标签:

【中文标题】从具有复合(分层)索引的 Pandas 数据框中选择行【英文标题】:Selecting rows from a Pandas dataframe with a compound (hierarchical) index 【发布时间】:2012-08-10 02:33:37 【问题描述】:

我怀疑这是微不足道的,但我还没有发现可以让我根据分层键的值从 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 看起来和我们预期的一样:

如果 df 没有在 group1 上被索引,我可以执行以下操作:

df['group1' == 'a']

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

df['a','c']

不。那也失败了。

那么我如何选择所有行:

    group1 == 'a' group1 == 'a' & group2 == 'c' group2 == 'c' ['a','b','c'] 中的组 1

【问题讨论】:

【参考方案1】:

尝试使用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

【讨论】:

知道必须有一个更简单的成语。谢谢! group1 in ['a','b','c']怎么样 df[[group1 in ['a', 'b', 'c'] for group1, group2 in df.index]] @lodagro 绝对有效,但我不知道为什么。你能解释一下[group1 in ['a', 'b', 'c'] for group1, group2 in df.index] 的工作原理吗? 使用的技术是布尔索引(另见pandas.pydata.org/pandas-docs/stable/…)。 Arthur 解释了我是如何创建布尔索引的,因为他指出还有其他方法可以创建 True/False 可迭代对象。但最终归结为问题第 4 部分的布尔索引。请注意,Arthur 在 GitHub 上打开了一个问题,请求简化此用例(请参阅github.com/pydata/pandas/issues/1766)。【参考方案2】:

如下语法可以使用:

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

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

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

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

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

【讨论】:

那行不通,因为'group1' == 'a' 只是 False,所以这只是df.ix[False]df.ix[0]。因此,df.ix['group1'=='a'] 将与 df.ix['group2'=='d'] 完全相同。 我们很接近了……但有些地方不太对劲。当我做df.ix['group2'=='d'] 时,我只得到一条记录......这是第一条记录,而不是 group2==d 的记录。 @JDLong:这是第一条记录,因为 'group2' == 'd' 为 False,即 0。这些比较中的每一个都被评估 first,因此它是.ix[0].ix[0,0].ix[0] 所以df.ix['a'].ix['d'] 工作......所以这涵盖了前两个例子。但是我如何只选择索引的第二部分? 我喜欢交换级别...但不确定如何将其用于超过 2 个级别的索引。自然,我的现实生活中的应用程序使用深度索引 :(【参考方案3】:

在 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 级。

【讨论】:

感谢您添加更新的解决方案。非常感谢。

以上是关于从具有复合(分层)索引的 Pandas 数据框中选择行的主要内容,如果未能解决你的问题,请参考以下文章

如何使用分层索引保存和检索 Pandas 数据帧?

如何从按连续变量分层的 Pandas 数据框中获取分层随机样本

ValueError:长度不匹配:在熊猫数据框中创建分层列时,预期的轴有 0 个元素

在 pandas 中,set_index 不创建分层索引

Pandas:使用循环和分层索引将多个 csv 文件导入数据帧

pandas构建复合索引数据(multiple index dataframe)pandas索引复合索引dataframe数据