46

我有带有 MultiIndex 列的 DataFrame,如下所示:

# sample data
col = pd.MultiIndex.from_arrays([['one', 'one', 'one', 'two', 'two', 'two'],
                                ['a', 'b', 'c', 'a', 'b', 'c']])
data = pd.DataFrame(np.random.randn(4, 6), columns=col)
data

样本数据

['a', 'c']从第二级只选择特定列(例如,不是范围)的正确、简单的方法是什么?

目前我正在这样做:

import itertools
tuples = [i for i in itertools.product(['one', 'two'], ['a', 'c'])]
new_index = pd.MultiIndex.from_tuples(tuples)
print(new_index)
data.reindex_axis(new_index, axis=1)

预期结果

然而,这感觉不是一个好的解决方案,因为我必须退出itertools,手动构建另一个 MultiIndex,然后重新索引(而且我的实际代码更加混乱,因为获取列列表并不那么简单)。我很确定必须有一些ix方法xs可以做到这一点,但是我尝试的一切都导致了错误。

4

7 回答 7

32

最直接的方法是使用.loc

>>> data.loc[:, (['one', 'two'], ['a', 'b'])]


   one       two     
     a    b    a    b
0  0.4 -0.6 -0.7  0.9
1  0.1  0.4  0.5 -0.3
2  0.7 -1.6  0.7 -0.8
3 -0.9  2.6  1.9  0.6

记住这一点[]()在处理MultiIndex对象时具有特殊含义:

(...) 元组被解释为一个多级

(...) 列表用于指定多个键 [在同一级别]

(...) 一个列表元组引用一个级别中的多个值

当我们编写(['one', 'two'], ['a', 'b'])时,元组中的第一个列表指定了我们想要的第一级的所有值MultiIndex。元组中的第二个列表指定了我们想要的第二级的所有值MultiIndex

编辑1:另一种可能性是用于slice(None)指定我们想要来自第一级的任何东西(类似于:在列表中切片)。然后指定我们想要的第二级中的哪些列。

>>> data.loc[:, (slice(None), ["a", "b"])]

   one       two     
     a    b    a    b
0  0.4 -0.6 -0.7  0.9
1  0.1  0.4  0.5 -0.3
2  0.7 -1.6  0.7 -0.8
3 -0.9  2.6  1.9  0.6

如果语法slice(None)确实吸引您,那么另一种可能性是使用pd.IndexSlice,它有助于使用更精细的索引来切片帧。

>>> data.loc[:, pd.IndexSlice[:, ["a", "b"]]]

   one       two     
     a    b    a    b
0  0.4 -0.6 -0.7  0.9
1  0.1  0.4  0.5 -0.3
2  0.7 -1.6  0.7 -0.8
3 -0.9  2.6  1.9  0.6

使用时pd.IndexSlice,我们可以:照常使用对帧进行切片。

来源:MultiIndex / 高级索引如何使用slice(None)

于 2019-07-11T00:22:08.667 回答
25

这不是很好,但也许:

>>> data
        one                           two                    
          a         b         c         a         b         c
0 -0.927134 -1.204302  0.711426  0.854065 -0.608661  1.140052
1 -0.690745  0.517359 -0.631856  0.178464 -0.312543 -0.418541
2  1.086432  0.194193  0.808235 -0.418109  1.055057  1.886883
3 -0.373822 -0.012812  1.329105  1.774723 -2.229428 -0.617690
>>> data.loc[:,data.columns.get_level_values(1).isin({"a", "c"})]
        one                 two          
          a         c         a         c
0 -0.927134  0.711426  0.854065  1.140052
1 -0.690745 -0.631856  0.178464 -0.418541
2  1.086432  0.808235 -0.418109  1.886883
3 -0.373822  1.329105  1.774723 -0.617690

会工作?

于 2013-08-27T16:22:58.537 回答
19

您可以使用其中任何一个,loc或者ix我将展示一个示例loc

data.loc[:, [('one', 'a'), ('one', 'c'), ('two', 'a'), ('two', 'c')]]

当您有一个 MultiIndexed DataFrame,并且您只想过滤掉一些列时,您必须传递与这些列匹配的元组列表。所以 itertools 方法非常好,但您不必创建新的 MultiIndex:

data.loc[:, list(itertools.product(['one', 'two'], ['a', 'c']))]
于 2013-08-27T16:16:56.000 回答
17

我认为有一个更好的方法(现在),这就是为什么我费心把这个问题(这是谷歌的最高结果)从阴影中拉出来:

data.select(lambda x: x[1] in ['a', 'b'], axis=1)

以快速而干净的单行方式提供您的预期输出:

        one                 two          
          a         b         a         b
0 -0.341326  0.374504  0.534559  0.429019
1  0.272518  0.116542 -0.085850 -0.330562
2  1.982431 -0.420668 -0.444052  1.049747
3  0.162984 -0.898307  1.762208 -0.101360

它主要是不言自明的,[1]指的是水平。

于 2015-10-11T18:19:03.310 回答
13

ixselect已弃用!

使用 和是pd.IndexSliceloc可取的选择。ixselect


DataFrame.locpd.IndexSlice

# Setup
col = pd.MultiIndex.from_arrays([['one', 'one', 'one', 'two', 'two', 'two'],
                                ['a', 'b', 'c', 'a', 'b', 'c']])
data = pd.DataFrame('x', index=range(4), columns=col)
data

  one       two      
    a  b  c   a  b  c
0   x  x  x   x  x  x
1   x  x  x   x  x  x
2   x  x  x   x  x  x
3   x  x  x   x  x  x

data.loc[:, pd.IndexSlice[:, ['a', 'c']]]

  one    two   
    a  c   a  c
0   x  x   x  x
1   x  x   x  x
2   x  x   x  x
3   x  x   x  x

您也可以选择一个axis参数来loc明确您从哪个轴索引:

data.loc(axis=1)[pd.IndexSlice[:, ['a', 'c']]]

  one    two   
    a  c   a  c
0   x  x   x  x
1   x  x   x  x
2   x  x   x  x
3   x  x   x  x

MultiIndex.get_level_values

调用data.columns.get_level_values过滤loc是另一种选择:

data.loc[:, data.columns.get_level_values(1).isin(['a', 'c'])]

  one    two   
    a  c   a  c
0   x  x   x  x
1   x  x   x  x
2   x  x   x  x
3   x  x   x  x

这自然可以允许在单个级别上过滤任何条件表达式。这是一个字典过滤的随机示例:

data.loc[:, data.columns.get_level_values(1) > 'b']

  one two
    c   c
0   x   x
1   x   x
2   x   x
3   x   x

可以在 Pandas MultiIndex DataFrame 中的Select rows 中找到有关切片和过滤 MultiIndex 的更多信息。

于 2019-01-23T23:00:20.137 回答
11

要选择列索引器第二级命名的所有列'a''c'可以使用切片器:

>>> data.loc[:, (slice(None), ('a', 'c'))]

        one                 two          
          a         c         a         c
0 -0.983172 -2.495022 -0.967064  0.124740
1  0.282661 -0.729463 -0.864767  1.716009
2  0.942445  1.276769 -0.595756 -0.973924
3  2.182908 -0.267660  0.281916 -0.587835

在这里,您可以阅读有关切片机的更多信息。

于 2016-06-17T03:43:55.120 回答
3

在我看来,使用 slice 对Marc P.回答稍微简单一点:

import pandas as pd
col = pd.MultiIndex.from_arrays([['one', 'one', 'one', 'two', 'two', 'two'], ['a', 'b', 'c', 'a', 'b', 'c']])
data = pd.DataFrame(np.random.randn(4, 6), columns=col)

data.loc[:, pd.IndexSlice[:, ['a', 'c']]]

        one                 two          
          a         c         a         c
0 -1.731008  0.718260 -1.088025 -1.489936
1 -0.681189  1.055909  1.825839  0.149438
2 -1.674623  0.769062  1.857317  0.756074
3  0.408313  1.291998  0.833145 -0.471879

从 pandas 0.21 左右开始,不推荐使用 .select 以支持 .loc

于 2018-08-22T12:51:17.627 回答