【问题标题】:Slicing a MultiIndex DataFrame by multiple values from a specified level通过指定级别的多个值对 MultiIndex DataFrame 进行切片
【发布时间】:2016-12-10 23:28:11
【问题描述】:

我想从二级级别将 MultiIndex DataFrame 分割为多个值。例如,在以下 DataFrame 中:

                val1  val2
ind1 ind2 ind3            
1    6    s1      10     8
2    7    s1      20     6
3    8    s2      30     4
4    9    s2      50     2
5    10   s3      60     0

我希望只切片 ind3 == s1 ind3 == s3:

           val1  val2
ind1 ind2            
1    6       10     8
2    7       20     6
5    10      60     0

最好的假设选项是将多个参数传递给.xs,因为可以显式声明所需的level

我显然可以连接所有按单值切片的数据帧:

In[2]: pd.concat([df.xs('s1',level=2), df.xs('s3',level=2)])
Out[2]:
           val1  val2
ind1 ind2            
1    6       10     8
2    7       20     6
5    10      60     0

但是 (a) 当使用超过 2 个值时,它很乏味且不那么可读,并且 (b) 对于大型 DataFrame,它非常重(或至少比多值切片选项(如果存在)。

这是构建示例 DataFrame 的代码

import pandas as pd
df = pd.DataFrame({'ind1':[1,2,3,4,5], 'ind2':[6,7,8,9,10], 'ind3':['s1','s1','s2','s2','s3'], 'val1':[10,20,30,50,60], 'val2':[8,6,4,2,0]}).set_index(['ind1','ind2','ind3'])

【问题讨论】:

    标签: python pandas dataframe multi-index


    【解决方案1】:

    与从 DataFrame 中进行的大多数选择一样,您可以使用掩码或索引器(在本例中为loc)。

    要获取掩码,您可以在 MultiIndex 上使用 get_level_values (docs),然后使用 isin (docs)。

    m = df.index.get_level_values('ind3').isin(['s1', 's3'])
    df[m].reset_index(level=2, drop=True)
    

    使用loc

    df.loc[(slice(None), slice(None), ['s1', 's3']), :].reset_index(level=2, drop=True)
    

    两个输出

               val1  val2
    ind1 ind2            
    1    6       10     8
    2    7       20     6
    5    10      60     0
    

    注意:loc 方式也可以写成 Alberto Garcia-Raboso 的答案。许多人更喜欢这种语法,因为它与 Indexloc 语法更一致。 the docs 讨论了这两种语法风格。

    【讨论】:

    • 感谢您的回复!请注意,我正在寻找结果 w.o. 'ind3'。
    【解决方案2】:

    您可以使用IndexSlice

    idx = pd.IndexSlice
    result = df.loc[idx[:, :, ['s1', 's3']], idx[:]]
    result.index = result.index.droplevel('ind3')
    print(result)
    

    输出:

               val1  val2
    ind1 ind2            
    1    6       10     8
    2    7       20     6
    5    10      60     0
    

    上面的第二行也可以写成

    result = df.loc(axis=0)[idx[:, :, ['s1', 's3']]]
    

    【讨论】:

    • IndexSlice - 不错!
    • @AlbertoGarcia-Raboso 感谢您的回复!第二个答案是第一个,所以我批准了,但你的也可以。
    • 这应该是选择的答案。漂亮!
    猜你喜欢
    • 2014-05-24
    • 2020-01-16
    • 1970-01-01
    • 1970-01-01
    • 2017-03-28
    • 2021-06-26
    • 1970-01-01
    • 2013-05-25
    相关资源
    最近更新 更多