用Python Pandas如何通过第二层级索引(或其他任意层级)切片多重索引?

23

有很多关于如何按级别[0]和级别1的范围切取多重索引的帖子。然而,我找不到适用于我的问题的解决方案;即,我需要针对级别[0]索引值的级别1索引范围。

数据框:从A到Z排序,级别为1到400;我需要每个级别[0](第一个)的前2个和后2个,但不是同时获取。

           Title Score
First Rank 
A     1    foo   100
      2    bar   90
      3    lime  80
      4    lame  70
B     1    foo   400
      2    lime  300
      3    lame  200
      4    dime  100

我正在尝试使用以下代码获取每个级别1最后2行的索引,但它只能正确地切片第一级[0]值。

[IN]  df.ix[x.index.levels[1][-2]:]
[OUT] 
               Title Score
    First Rank 
    A     3    lime  80
          4    lame  70
    B     1    foo   400
          2    lime  300
          3    lame  200
          4    dime  100

前两行可以通过交换索引来获得,但我无法使最后两行起作用。

df.index = df.index.swaplevel("Rank", "First")
df= df.sortlevel() #to sort by Rank
df.ix[1:2] #Produces the first 2 ranks with 2 level[1] (First) each.
           Title Score
Rank First 
1     A    foo   100
      B    foo   400
2     A    bar   90
      B    lime  300

当然,我可以把这个交换回去得到这个:

df2 = df.ix[1:2]
df2.index = ttt.index.swaplevel("First","rank") #change the order of the indices back.
df2.sortlevel()
               Title Score
    First Rank 
    A     1    foo   100
          2    bar   90
    B     1    foo   400
          2    lime  300

希望得到关于相同过程的任何帮助:

  • 最后2行为索引1(排名)
  • 获得前2行更好的方法

根据@ako的反馈编辑如下:

使用pd.IndexSlice确实使得对任意级别的索引都能轻松切片。以下是更通用的解决方案以及获取前两行和后两行的步骤。更多信息请参见:http://pandas.pydata.org/pandas-docs/stable/advanced.html#using-slicers

"""    
Slicing a dataframe at the level[2] index of the
major axis (row) for specific and at the level[1] index for columns.

"""
    df.loc[idx[:,:,['some label','another label']],idx[:,'yet another label']]

"""
Thanks to @ako below is my solution, including how I
get the top and last 2 rows.
"""
    idx = pd.IndexSlice
    # Top 2
    df.loc[idx[:,[1,2],:] #[1,2] is NOT a row index, it is the rank label. 
    # Last 2
    max = len(df.index.levels[df.index.names.index("rank")]) # unique rank labels
    last2=[x for x in range(max-2,max)]
    df.loc[idx[:,last2],:] #for last 2 - assuming all level[0] have the same lengths.

如果您对切片和过滤多级索引数据框更感兴趣,请查看我的文章:如何切片或过滤MultiIndex DataFrame levels? - cs95
2个回答

40

使用索引器在任意维度上切片任意值--只需传递一个列表,其中包含该维度所需的级别/值。

idx = pd.IndexSlice
df.loc[idx[:,[3,4]],:]

           Title  Score
First Rank             
A     3     lime     80
      4     lame     70
B     3     lame    200
      4     dime    100

为了复现数据:

from io import StringIO

s="""
First Rank Title Score
A      1    foo   100
A      2    bar   90
A      3    lime  80
A      4    lame  70
B      1    foo   400
B      2    lime  300
B      3    lame  200
B      4    dime  100
"""
df = pd.read_csv(StringIO(s),
                 sep='\s+',
                 index_col=["First", "Rank"])

4
在StackOverflow的有关Pandas MultiIndex索引的答案中,这个解决方案似乎是最干净、并且被低估了。 - Gene Burinsky
注意在列轴上包括“:”,否则会出现 KeyError。 - Peter Hansen
在1.4.1版本中,它会给出一个警告:"使用嵌套标签的MultiIndex进行索引的行为已被弃用"。 - undefined
我希望他们决定重新设计MultIndexing。在我看来,语法实在是有些笨拙。 - undefined

11

在多级索引中按任意级别切片的另一种方法是使用slice(None).loc[]。对于多级索引,.loc[]将采用元组,使用slice(None)表示不对特定索引进行切片,然后为正在切片的索引传递单个项目或列表。希望可以帮助未来的读者。

df.loc[ ( slice(None), [3, 4] ),  : ]

在我看来,这个答案更简洁。访问多重索引的语法有点奇怪。我想知道Pandas的开发人员是否考虑过让它更直观一些。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接