从pandas MultiIndex中选择列

met*_*mit 19 python hierarchical multi-index pandas

我有DataFrame和MultiIndex列,如下所示:

# 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
Run Code Online (Sandbox Code Playgroud)

样本数据

['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)
Run Code Online (Sandbox Code Playgroud)

预期结果

然而,它不是一个好的解决方案,因为我必须淘汰itertools,手工构建另一个MultiIndex,然后重新索引(我的实际代码甚至更麻烦,因为列列表不是那么容易获取).我很确定必须有一些ixxs这样做,但我尝试的一切都导致了错误.

Gui*_*omé 24

最直接的方法是.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
Run Code Online (Sandbox Code Playgroud)

记住这一点[]()在处理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
Run Code Online (Sandbox Code Playgroud)

如果语法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
Run Code Online (Sandbox Code Playgroud)

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

来源:MultiIndex/Advanced Indexing如何使用slice(None)


Foo*_*Bar 16

我认为有一个更好的方法(现在),这就是为什么我打扰这个问题(这是最好的谷歌结果)出于阴影:

data.select(lambda x: x[1] in ['a', 'b'], axis=1)
Run Code Online (Sandbox Code Playgroud)

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

        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
Run Code Online (Sandbox Code Playgroud)

它主要是自我解释,[1]指的是水平.

  • 注意:`FutureWarning:'select'已弃用,将在以后的版本中删除.您可以使用.loc [labels.map(crit)]作为替代品 (4认同)

Vik*_*kez 14

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

data.loc[:, [('one', 'a'), ('one', 'c'), ('two', 'a'), ('two', 'c')]]
Run Code Online (Sandbox Code Playgroud)

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

data.loc[:, list(itertools.product(['one', 'two'], ['a', 'c']))]
Run Code Online (Sandbox Code Playgroud)


DSM*_*DSM 8

这不是很好,但也许:

>>> 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
Run Code Online (Sandbox Code Playgroud)

会工作?


Mar*_* P. 8

要选择所有已命名的列'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
Run Code Online (Sandbox Code Playgroud)

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


cs9*_*s95 5

ixselect已弃用!

使用的pd.IndexSlice品牌loc更可取的选择,以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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

您还可以选择一个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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

有关对MultiIndex进行切片和过滤的更多信息,请参见pandas MultiIndex DataFrame中的Select行