在 pandas MultiIndex DataFrame 中选择行

Select rows in pandas MultiIndex DataFrame

提问人:cs95 提问时间:12/26/2018 最后编辑:cs95 更新时间:5/23/2023 访问量:127816

问:

选择/筛选索引为 MultiIndex 的数据帧行的最常见 pandas 方法是什么?

  • 基于单个值/标签的切片
  • 基于一个或多个级别的多个标签进行切片
  • 筛选布尔条件和表达式
  • 哪些方法适用于什么情况

简单起见的假设:

  1. 输入 DataFrame 没有重复的索引键
  2. 下面的输入数据帧只有两个级别。(此处显示的大多数解决方案都推广到 N 级)

输入示例:

mux = pd.MultiIndex.from_arrays([
    list('aaaabbbbbccddddd'),
    list('tuvwtuvwtuvwtuvw')
], names=['one', 'two'])

df = pd.DataFrame({'col': np.arange(len(mux))}, mux)

         col
one two     
a   t      0
    u      1
    v      2
    w      3
b   t      4
    u      5
    v      6
    w      7
    t      8
c   u      9
    v     10
d   w     11
    t     12
    u     13
    v     14
    w     15

问题 1:选择单个项目

如何选择级别“一”中包含“a”的行?

         col
one two     
a   t      0
    u      1
    v      2
    w      3

此外,我如何才能在输出中删除级别“一”?

     col
two     
t      0
u      1
v      2
w      3

问题 1b
如何在级别“two”上对值为“t”的所有行进行切片?

         col
one two     
a   t      0
b   t      4
    t      8
d   t     12

问题 2:在关卡中选择多个值

如何选择与级别“一”中的“b”和“d”项相对应的行?

         col
one two     
b   t      4
    u      5
    v      6
    w      7
    t      8
d   w     11
    t     12
    u     13
    v     14
    w     15

问题 2b
如何获得与“二”级中“t”和“w”相对应的所有值?

         col
one two     
a   t      0
    w      3
b   t      4
    w      7
    t      8
d   w     11
    t     12
    w     15

问题 3:切割单个横截面(x, y)

如何从中检索横截面,即具有索引特定值的单行?具体来说,我如何检索 的横截面,由下式给出df('c', 'u')

         col
one two     
c   u      9

问题 4:切割多个横截面[(a, b), (c, d), ...]

如何选择对应于 和 的两行?('c', 'u')('a', 'w')

         col
one two     
c   u      9
a   w      3

问题 5:每级切片一件物品

如何检索与级别“一”中的“a”或级别“二”中的“t”对应的所有行?

         col
one two     
a   t      0
    u      1
    v      2
    w      3
b   t      4
    t      8
d   t     12

问题 6:任意切片

如何对特定的横截面进行切片?对于“a”和“b”,我想选择所有具有子级别“u”和“v”的行,对于“d”,我想选择具有子级别“w”的行。

         col
one two     
a   u      1
    v      2
b   u      5
    v      6
d   w     11
    w     15

问题 7 将使用由数字级别组成的独特设置:

np.random.seed(0)
mux2 = pd.MultiIndex.from_arrays([
    list('aaaabbbbbccddddd'),
    np.random.choice(10, size=16)
], names=['one', 'two'])

df2 = pd.DataFrame({'col': np.arange(len(mux2))}, mux2)

         col
one two     
a   5      0
    0      1
    3      2
    3      3
b   7      4
    9      5
    3      6
    5      7
    2      8
c   4      9
    7     10
d   6     11
    8     12
    8     13
    1     14
    6     15

问题 7:在多索引的各个水平上按数值不等式进行过滤

如何获取级别“two”中的值大于 5 的所有行?

         col
one two     
b   7      4
    9      5
c   7     10
d   6     11
    8     12
    8     13
    6     15

注意:本文不会介绍如何创建多索引,如何对它们执行赋值操作,或任何与性能相关的讨论(这些是另一个时间的单独主题)。

Python Pandas DataFrame Slice 多索引

评论

0赞 Jorge Torres 4/20/2021
这看起来像是 dfsql df.sql(<SQL select statement>) github.com/mindsdb/dfsql medium.com/riselab/ 的一个很好的案例......
0赞 Yilmaz 9/2/2023
我想知道为什么这个问题从未结束。它问 7 个问题

答:

368赞 cs95 12/26/2018 #1

MultiIndex / 高级索引

注意:这篇文章将按以下方式构建:

  1. OP中提出的问题将逐一解决
  2. 对于每个问题,将演示一种或多种适用于解决此问题并获得预期结果的方法。

注释s(很像这个)将包含在有兴趣了解其他功能、实现细节、 以及手头主题的其他粗略信息。这些笔记已经 通过搜索文档并发现各种晦涩难懂的内容进行编译 功能,以及我自己的(公认有限的)经验。

所有代码示例均已在 pandas v0.23.4、python3.7 上创建和测试。如果某些内容不清楚,或事实不正确,或者您没有 查找适用于您的用例的解决方案,请随时 建议编辑,在评论中请求澄清,或打开新的 问题。。。。如适用。

以下是一些常见的成语(以下简称“四成语”)的介绍,我们将经常重温

  1. DataFrame.loc - 按标签 (+ pd.IndexSlice 用于涉及切片的更复杂应用程序)

  2. DataFrame.xs - 从 Series/DataFrame 中提取特定横截面。

  3. DataFrame.query - 动态指定切片和/或筛选操作(即,作为动态计算的表达式。比其他方案更适用于某些方案。另请参阅文档的这一部分,了解如何查询 MultiIndexes。

  4. 使用使用 MultiIndex.get_level_values 生成的掩码进行布尔索引(通常与 Index.isin 结合使用,尤其是在使用多个值进行筛选时)。这在某些情况下也非常有用。

根据四个成语来研究各种切片和过滤问题,以更好地理解什么可以应用于给定的情况,这将是有益的。重要的是要明白,并非所有的习语在每种情况下都能同样出色地工作(如果有的话)。如果一个成语没有被列为下面某个问题的潜在解决方案,这意味着该成语不能有效地应用于该问题。


第1项质询

如何选择级别“一”中包含“a”的行?

         col
one two     
a   t      0
    u      1
    v      2
    w      3

您可以使用 作为适用于大多数情况的通用解决方案:loc

df.loc[['a']]

在这一点上,如果你得到

TypeError: Expected tuple, got str

这意味着您使用的是旧版本的 pandas。考虑升级!否则,请使用 .df.loc[('a', slice(None)), :]

或者,您可以使用此处,因为我们正在提取单个横截面。请注意 and 参数(此处可以假定合理的默认值)。xslevelsaxis

df.xs('a', level=0, axis=0, drop_level=False)
# df.xs('a', drop_level=False)

在这里,需要参数来防止在结果中丢弃级别“一”(我们切片的级别)。drop_level=Falsexs

这里的另一个选项是使用:query

df.query("one == 'a'")

如果索引没有名称,则需要将查询字符串更改为 。"ilevel_0 == 'a'"

最后,使用:get_level_values

df[df.index.get_level_values('one') == 'a']
# If your levels are unnamed, or if you need to select by position (not label),
# df[df.index.get_level_values(0) == 'a']

此外,我如何才能在输出中删除级别“一”?

     col
two     
t      0
u      1
v      2
w      3

这可以使用以下任一方法轻松完成

df.loc['a'] # Notice the single string argument instead the list.

df.xs('a', level=0, axis=0, drop_level=True)
# df.xs('a')

请注意,我们可以省略该参数(假定默认情况下是)。drop_levelTrue

注意
您可能会注意到,筛选的 DataFrame 可能仍具有所有级别,即使它们在打印 DataFrame 时不显示。例如

v = df.loc[['a']]
print(v)
         col
one two     
a   t      0
    u      1
    v      2
    w      3

print(v.index)
MultiIndex(levels=[['a', 'b', 'c', 'd'], ['t', 'u', 'v', 'w']],
           labels=[[0, 0, 0, 0], [0, 1, 2, 3]],
           names=['one', 'two'])

您可以使用以下MultiIndex.remove_unused_levels摆脱这些级别:

v.index = v.index.remove_unused_levels()
print(v.index)
MultiIndex(levels=[['a'], ['t', 'u', 'v', 'w']],
           labels=[[0, 0, 0, 0], [0, 1, 2, 3]],
           names=['one', 'two'])

问题 1b

如何在级别“two”上切分值为“t”的所有行?

         col
one two     
a   t      0
b   t      4
    t      8
d   t     12

直观地说,你会想要一些涉及 slice() 的东西:

df.loc[(slice(None), 't'), :]

它只是工作! ™ 但它很笨拙。我们可以在此处使用 API 促进更自然的切片语法。pd.IndexSlice

idx = pd.IndexSlice
df.loc[idx[:, 't'], :]

这要干净得多。

注意
:为什么需要跨列的尾随切片?这是因为,可用于沿两个轴(或)进行选择和切片。没有明确说明切片的轴 是要完成的,操作变得模棱两可。请参阅切片文档中的大红框。
:locaxis=0axis=1

如果要消除任何歧义,请接受一个参数:locaxis

df.loc(axis=0)[pd.IndexSlice[:, 't']]

如果没有参数(即,只是通过执行),则假定切片在列上, 在这种情况下,将提出一个。axisdf.loc[pd.IndexSlice[:, 't']]KeyError

这在切片器中记录。但是,出于本文的目的,我们将明确指定所有轴。

用 ,它是xs

df.xs('t', axis=0, level=1, drop_level=False)

用 ,它是query

df.query("two == 't'")
# Or, if the first level has no name, 
# df.query("ilevel_1 == 't'") 

最后,使用 ,您可以做到get_level_values

df[df.index.get_level_values('two') == 't']
# Or, to perform selection by position/integer,
# df[df.index.get_level_values(1) == 't']

都是一样的效果。


第2项质询

如何选择与级别“一”中的“b”和“d”项相对应的行?

         col
one two     
b   t      4
    u      5
    v      6
    w      7
    t      8
d   w     11
    t     12
    u     13
    v     14
    w     15

使用 loc,通过指定列表以类似的方式完成此操作。

df.loc[['b', 'd']]

要解决上述选择“b”和“d”的问题,还可以使用:query

items = ['b', 'd']
df.query("one in @items")
# df.query("one == @items", parser='pandas')
# df.query("one in ['b', 'd']")
# df.query("one == ['b', 'd']", parser='pandas')

注意:
是的,默认解析器是 ,但重要的是要强调此语法不是传统的 python。这 Pandas 解析器生成的解析树与 表达。这样做是为了使某些操作更直观 指定。有关更多信息,请阅读我关于使用 pd.eval() 在熊猫中进行动态表达式评估的文章。
'pandas'

并且,使用 + :get_level_valuesIndex.isin

df[df.index.get_level_values("one").isin(['b', 'd'])]

问题 2b

如何获得级别“two”中对应于“t”和“w”的所有值?

         col
one two     
a   t      0
    w      3
b   t      4
    w      7
    t      8
d   w     11
    t     12
    w     15

使用 ,这只有在与 结合时才有可能。locpd.IndexSlice

df.loc[pd.IndexSlice[:, ['t', 'w']], :] 

第一个冒号表示切过第一层。随着所查询关卡深度的增加,您将需要指定更多切片,每个关卡一个切片。但是,除了被切片的级别之外,您不需要指定更多级别。:pd.IndexSlice[:, ['t', 'w']]

使用 ,这是query

items = ['t', 'w']
df.query("two in @items")
# df.query("two == @items", parser='pandas') 
# df.query("two in ['t', 'w']")
# df.query("two == ['t', 'w']", parser='pandas')

使用和(类似于上述):get_level_valuesIndex.isin

df[df.index.get_level_values('two').isin(['t', 'w'])]

第3项质询

如何检索横截面,即具有特定值的单行 对于来自 ?具体来说,我该如何取回十字架 部分 ,由下式给出df('c', 'u')

         col
one two     
c   u      9

通过指定键元组来使用:loc

df.loc[('c', 'u'), :]

df.loc[pd.IndexSlice[('c', 'u')]]

注意:
此时,您可能会遇到如下所示的 PerformanceWarning

PerformanceWarning: indexing past lexsort depth may impact performance.

这仅意味着您的索引未排序。Pandas 依赖于正在排序的索引(在本例中,按字典法排序,因为我们处理的是字符串值)以获得最佳搜索和检索。一个快速的解决方法是对你的 DataFrame 提前使用 DataFrame.sort_index。如果您打算这样做,从性能的角度来看,这是特别可取的 多个此类查询串联在一起:

df_sort = df.sort_index()
df_sort.loc[('c', 'u')]

也可以使用 MultiIndex.is_lexsorted() 来检查索引是否 是否排序。此函数相应地返回 OR。 您可以调用此函数来确定是否进行其他排序 步骤是否为必填项。TrueFalse

使用 ,这再次简单地传递一个元组作为第一个参数,并将所有其他参数设置为适当的默认值:xs

df.xs(('c', 'u'))

有了 ,事情就变得有点笨拙了:query

df.query("one == 'c' and two == 'u'")

你现在可以看到,这将是相对难以概括的。但对于这个特定问题仍然可以。

对于跨多个级别的访问,仍然可以使用,但不建议这样做:get_level_values

m1 = (df.index.get_level_values('one') == 'c')
m2 = (df.index.get_level_values('two') == 'u')
df[m1 & m2]

第4项质询

如何选择对应于 和 的两行?('c', 'u')('a', 'w')

         col
one two     
c   u      9
a   w      3

使用 ,这仍然很简单:loc

df.loc[[('c', 'u'), ('a', 'w')]]
# df.loc[pd.IndexSlice[[('c', 'u'), ('a', 'w')]]]

使用 ,您需要通过遍历横截面和级别来动态生成查询字符串:query

cses = [('c', 'u'), ('a', 'w')]
levels = ['one', 'two']
# This is a useful check to make in advance.
assert all(len(levels) == len(cs) for cs in cses) 

query = '(' + ') or ('.join([
    ' and '.join([f"({l} == {repr(c)})" for l, c in zip(levels, cs)]) 
    for cs in cses
]) + ')'

print(query)
# ((one == 'c') and (two == 'u')) or ((one == 'a') and (two == 'w'))

df.query(query)

100%不推荐!但这是可能的。

如果我有多个级别怎么办?
在这种情况下,一种选择是使用 droplevel 删除您未检查的级别,然后使用 isin 测试成员资格,然后对最终结果进行布尔索引。

df[df.index.droplevel(unused_level).isin([('c', 'u'), ('a', 'w')])]

第5项质询

如何检索级别“一”中与“a”对应的所有行或 “二”级中的“t”?

         col
one two     
a   t      0
    u      1
    v      2
    w      3
b   t      4
    t      8
d   t     12

这实际上很难做到,同时确保正确性仍然保持代码清晰度。 不正确,则解释为(即选择横截面)。您可以想到一个解决方案来单独处理每个标签:locdf.loc[pd.IndexSlice['a', 't']]df.loc[pd.IndexSlice[('a', 't')]]pd.concat

pd.concat([
    df.loc[['a'],:], df.loc[pd.IndexSlice[:, 't'],:]
])

         col
one two     
a   t      0
    u      1
    v      2
    w      3
    t      0   # Does this look right to you? No, it isn't!
b   t      4
    t      8
d   t     12

但是您会注意到其中一行是重复的。这是因为该行同时满足两个切片条件,因此出现了两次。相反,您需要这样做

v = pd.concat([
        df.loc[['a'],:], df.loc[pd.IndexSlice[:, 't'],:]
])
v[~v.index.duplicated()]

但是,如果您的 DataFrame 本身包含重复的索引(您想要的),则不会保留它们。使用时要格外小心

有了 ,这非常简单:query

df.query("one == 'a' or two == 't'")

有了 ,这仍然很简单,但不那么优雅:get_level_values

m1 = (df.index.get_level_values('one') == 'a')
m2 = (df.index.get_level_values('two') == 't')
df[m1 | m2] 

第6项质询

如何对特定的横截面进行切片?对于“a”和“b”,我想选择所有具有子级别“u”和“v”的行,并且 对于“d”,我想选择子级别为“w”的行。

         col
one two     
a   u      1
    v      2
b   u      5
    v      6
d   w     11
    w     15

这是我添加的一个特例,以帮助理解四个成语的适用性——这是一个它们都无法有效工作的情况,因为切片非常具体,并且不遵循任何实际模式。

通常,像这样的切片问题需要显式地将键列表传递给 。一种方法是:loc

keys = [('a', 'u'), ('a', 'v'), ('b', 'u'), ('b', 'v'), ('d', 'w')]
df.loc[keys, :]

如果你想节省一些打字,你会认识到对“a”、“b”及其子级别进行切片是有规律的,因此我们可以将切片任务分成两部分,结果如下:concat

pd.concat([
     df.loc[(('a', 'b'), ('u', 'v')), :], 
     df.loc[('d', 'w'), :]
   ], axis=0)

“a”和“b”的切片规范稍微简洁一些,因为每个级别索引的相同子级别都是相同的。(('a', 'b'), ('u', 'v'))


第7项质询

如何获取级别“two”中的值大于 5 的所有行?

         col
one two     
b   7      4
    9      5
c   7     10
d   6     11
    8     12
    8     13
    6     15

这可以使用 来完成 ,query

df2.query("two > 5")

和。get_level_values

df2[df2.index.get_level_values('two') > 5]

注意
与此示例类似,我们可以使用这些构造根据任何任意条件进行筛选。通常,记住这一点是很有用的,并且专门用于基于标签的索引,而 和 有助于构建常规条件掩码 用于过滤。
locxsqueryget_level_values


奖金问题

如果我需要切一列怎么办?MultiIndex

实际上,这里的大多数解决方案也适用于列,只是略有改动。考虑:

np.random.seed(0)
mux3 = pd.MultiIndex.from_product([
        list('ABCD'), list('efgh')
], names=['one','two'])

df3 = pd.DataFrame(np.random.choice(10, (3, len(mux))), columns=mux3)
print(df3)

one  A           B           C           D         
two  e  f  g  h  e  f  g  h  e  f  g  h  e  f  g  h
0    5  0  3  3  7  9  3  5  2  4  7  6  8  8  1  6
1    7  7  8  1  5  9  8  9  4  3  0  3  5  0  2  3
2    8  1  3  3  3  7  0  1  9  9  0  4  7  3  2  7

这些是您需要对四个习语进行以下更改,以使它们与列一起使用。

  1. 要使用 进行切片,请使用loc

     df3.loc[:, ....] # Notice how we slice across the index with `:`. 
    

     df3.loc[:, pd.IndexSlice[...]]
    
  2. 要根据需要使用,只需传递一个参数。xsaxis=1

  3. 您可以使用 直接访问列级别值。然后,您将需要执行以下操作df.columns.get_level_values

     df.loc[:, {condition}] 
    

    其中表示使用 构建的某个条件。{condition}columns.get_level_values

  4. 若要使用 ,唯一的选择是转置、查询索引,然后再次转置:query

     df3.T.query(...).T
    

    不推荐使用其他 3 个选项之一。

19赞 r a 11/4/2019 #2

最近,我遇到了一个用例,我有一个 3+ 级多索引数据帧,我无法使上述任何解决方案产生我正在寻找的结果。上述解决方案很有可能当然适用于我的用例,我尝试了几种,但是我无法让它们在我可用的时间内工作。

我远非专家,但我偶然发现了一个未在上面的综合答案中列出的解决方案。我不保证这些解决方案在任何方面都是最佳的。

这是获得与上面的问题 #6 略有不同的结果的不同方法。(可能还有其他问题)

具体来说,我正在寻找:

  1. 一种从指数的一个级别选择两个+值,从指数的另一个级别选择单个值的方法,以及
  2. 一种将上一个操作的索引值保留在数据帧输出中的方法。

作为齿轮中的猴子扳手(但完全可以修复):

  1. 索引未命名。

在下面的玩具数据框上:

    index = pd.MultiIndex.from_product([['a','b'],
                               ['stock1','stock2','stock3'],
                               ['price','volume','velocity']])

    df = pd.DataFrame([1,2,3,4,5,6,7,8,9,
                      10,11,12,13,14,15,16,17,18], 
                       index)

                        0
    a stock1 price      1
             volume     2
             velocity   3
      stock2 price      4
             volume     5
             velocity   6
      stock3 price      7
             volume     8
             velocity   9
    b stock1 price     10
             volume    11
             velocity  12
      stock2 price     13
             volume    14
             velocity  15
      stock3 price     16
             volume    17
             velocity  18

当然,使用以下方法有效:

    df.xs(('stock1', 'velocity'), level=(1,2))

        0
    a   3
    b  12

但是我想要一个不同的结果,所以我得到这个结果的方法是:

   df.iloc[df.index.isin(['stock1'], level=1) & 
           df.index.isin(['velocity'], level=2)] 

                        0
    a stock1 velocity   3
    b stock1 velocity  12

如果我想要一个级别的两个 + 值和另一个级别的单个(或 2+)值:

    df.iloc[df.index.isin(['stock1','stock3'], level=1) & 
            df.index.isin(['velocity'], level=2)] 

                        0
    a stock1 velocity   3
      stock3 velocity   9
    b stock1 velocity  12
      stock3 velocity  18

上述方法可能有点笨拙,但我发现它满足了我的需求,并且作为奖励,我更容易理解和阅读。

评论

2赞 fpersyn 11/22/2022
改用 IndexSlice 将避免重复分析索引。您可以使用 cs95 实现与 cs95 相同的无损结果。df.loc[pd.IndexSlice[:, 'stock1', 'velocity'], :]df.loc[pd.IndexSlice[:, ['stock1', 'stock3'], 'velocity'], :]
1赞 Jorge Torres 4/20/2021 #3

这看起来像是 dfsql 的一个很好的案例

df.sql(<SQL select statement>)

https://github.com/mindsdb/dfsql

关于它的完整文章在这里:

https://medium.com/riselab/why-every-data-scientist-using-pandas-needs-modin-bringing-sql-to-dataframes-3b216b29a7c0

评论

2赞 buhtz 9/15/2021
不要只提供链接。请补充一些例子。为相应的子问题添加解决方案。
1赞 double0darbo 3/26/2022 #4

我长期以来一直使用并欣赏这个问题,以及@cs95的回答,它非常彻底,可以处理所有情况。与@r-a的答案类似,我也想找到一种方法来处理包含多个级别的多个索引。

我终于找到了一种方法,可以在给定级别或命名索引的情况下获得任意数量的切片,这能够处理上面提出的几个问题。这里的主要改进是不必对多个索引或切片进行解析或 with。slice(None):pd.IndexSlice

import pandas as pd

def slice_df_by(df_, slice_by=["Oman", "Nairobi",], slice_idx='country'):
    idxn = df_.index.names.index(slice_idx)
    return df_.loc[tuple([slice(None)]*idxn +[slice_by] ), :]

gender = tuple(["male", "female"]*6)
thrown = tuple(["rock", "scissors", "paper"]*4) 
country = tuple(["Nairobi", "Oman", "Djibouti", "Belize"]*3) 
names = tuple(["Chris", "Pat", "Michele", "Thomy", "Musa", "Casey"]*2)

tuples = list(zip(gender, thrown, country, names))

idx = pd.MultiIndex.from_tuples(tuples, 
                                names=["gender", "thrown", "country", "name"])

df = pd.DataFrame({'Count A': [12., 70., 30., 20.]*3, 
                   'Count B': [12., 70., 30., 20.]*3}, index=idx)

这样做的好处是,您可以将这些调用的任意组合添加到函数中,以获得更复杂的切片,同时仅使用索引名称和值列表。slice_df_by

print(slice_df_by(df))

                                 Count A  Count B
gender thrown   country name                     
female scissors Oman    Pat         70.0     70.0
       paper    Oman    Casey       70.0     70.0
       rock     Oman    Thomy       70.0     70.0
male   rock     Nairobi Chris       12.0     12.0
       scissors Nairobi Musa        12.0     12.0
       paper    Nairobi Michele     12.0     12.0

正如@r所指出的,问题在于没有命名指数。使用这里的方法有很多方法可以满足这一点,例如或一些这样的方法:df.index.names = ["names", "for", "the", "indices"]

idxz = lambda ixln=4: [chr(i) for i in np.arange(ixln)+65]
df.index.names = idxz(len(df.index.names))
print(idxz())
Out[132]: ['A', 'B', 'C', 'D']
0赞 sammywemmy 11/16/2022 #5

一种选择是使用 pyjanitor 的 select_rows

# pip install pyjanitor
import pandas as pd
import janitor

第1项质询

如何选择级别“一”中包含“a”的行?

df.select_rows('a') 
         col
one two     
a   t      0
    u      1
    v      2
    w      3

此外,我如何才能在输出中删除级别“一”?

df.select_rows('a').droplevel('one') 
     col
two     
t      0
u      1
v      2
w      3

问题 1b

如何在级别“two”上切分值为“t”的所有行?

         col
one two     
a   t      0
b   t      4
    t      8
d   t     12

在此处使用字典,将级别指定为键,然后传递标签以选择:

df.select_rows({'two':'t'})
         col
one two     
a   t      0
b   t      4
    t      8
d   t     12

第2项质询

如何选择与级别“一”中的“b”和“d”项相对应的行?

         col
one two     
b   t      4
    u      5
    v      6
    w      7
    t      8
d   w     11
    t     12
    u     13
    v     14
    w     15

由于选择在单个级别上,因此请传递标签列表:

df.select_rows(['b','d'])
         col
one two     
b   t      4
    u      5
    v      6
    w      7
    t      8
d   w     11
    t     12
    u     13
    v     14
    w     15

问题 2b

如何获得级别“two”中对应于“t”和“w”的所有值?

         col
one two     
a   t      0
    w      3
b   t      4
    w      7
    t      8
d   w     11
    t     12
    w     15

使用字典:

df.select_rows({'two':['t','w']})
         col
one two     
a   t      0
b   t      4
    t      8
d   t     12
a   w      3
b   w      7
d   w     11
    w     15

第3项质询

如何检索横截面,即具有特定值的单行 对于来自 ?具体来说,我该如何取回十字架 部分 ,由下式给出df('c', 'u')

         col
one two     
c   u      9

我们要跨越级别(水平,而不是垂直),需要一个元组:

# sort required to avoid lexsort performance warning
df.sort_index().select_rows(('c','u'))
         col
one two     
c   u      9

第4项质询

如何选择对应于 和 的两行?('c', 'u')('a', 'w')

         col
one two     
c   u      9
a   w      3

select_rows接受多个变量参数:

df.sort_index().select_rows(('c','u'), ('a','w'))
         col
one two     
c   u      9
a   w      3

第5项质询

如何检索级别“一”中与“a”对应的所有行或 “二”级中的“t”?

         col
one two     
a   t      0
    u      1
    v      2
    w      3
b   t      4
    t      8
d   t     12
df.select_rows('a', {'two':'t'})
         col
one two     
a   t      0
    u      1
    v      2
    w      3
    t      0
b   t      4
    t      8
d   t     12

第6项质询

如何对特定的横截面进行切片?对于“a”和“b”,我想选择所有具有子级别“u”和“v”的行,并且 对于“d”,我想选择子级别为“w”的行。

         col
one two     
a   u      1
    v      2
b   u      5
    v      6
d   w     11
    w     15
df.sort_index().select_rows({'one':['a','b'], 'two':['u','v']}, ('d','w'))
         col
one two     
a   u      1
    v      2
b   u      5
    v      6
d   w     11
    w     15

第7项质询

如何获取级别“two”中的值大于 5 的所有行?

         col
one two     
b   7      4
    9      5
c   7     10
d   6     11
    8     12
    8     13
    6     15

使用字典,您可以传递一个函数,只要它可以在 Index 对象上计算即可:

df2.select_rows({'two': lambda df: df > 5})
         col
one two     
b   7      4
    9      5
c   7     10
d   6     11
    8     12
    8     13
    6     15

您可以使用 select_columns 函数选择列。还有一个通用的选择函数,用于对行和列进行选择。

这些函数是可扩展的:让我们看看它是如何与@double0darbo答案一起工作的:

df.select_rows({'country':['Oman', 'Nairobi']})
                                 Count A  Count B
gender thrown   country name                     
female scissors Oman    Pat         70.0     70.0
       paper    Oman    Casey       70.0     70.0
       rock     Oman    Thomy       70.0     70.0
male   rock     Nairobi Chris       12.0     12.0
       scissors Nairobi Musa        12.0     12.0
       paper    Nairobi Michele     12.0     12.0

也尝试@r答案:

df.select_rows({1:'stock1', 2:'velocity'})
                    0
a stock1 velocity   3
b stock1 velocity  12

df.select_rows({1:['stock1','stock3'], 2:'velocity'})
                    0
a stock1 velocity   3
b stock1 velocity  12
a stock3 velocity   9
b stock3 velocity  18

df.select_rows({0:slice('a',None), 1:['stock1','stock3'], 2:'velocity'})
                    0
a stock1 velocity   3
  stock3 velocity   9
b stock1 velocity  12
  stock3 velocity  18

1赞 fantabolous 4/28/2023 #6

公认的答案非常好,但在仅在第 2 级切片时提供了更简洁的解决方案,例如问题 1b 和 2b。它消除了 和 的必要性。.loc(axis=0)get_level_valuespd.IndexSlice


问题 1b

如何在级别“two”上切分值为“t”的所有行?

         col
one two     
a   t      0
b   t      4
    t      8
d   t     12

df.loc(axis=0)[:,'t']就是你所需要的。

问题 2b

如何获得级别“two”中对应于“t”和“w”的所有值?

         col
one two     
a   t      0
    w      3
b   t      4
    w      7
    t      8
d   w     11
    t     12
    w     15

df.loc(axis=0)[:,['t', 'w']]再次是你所需要的。

axis=0等效于 。axis='rows'

同样,要对 MultiIndex 列进行切片,请使用.loc(axis=1).loc(axis='columns')

0赞 Jonas Hörsch 5/23/2023 #7

使用 pandas 多索引通常非常困难,因此,我创建了一个小型辅助库 pandas-indexing 来简化它们的使用,它包含一组选择器,可以优雅地查询到多索引中:

from pandas_indexing import isin

第1项质询

如何选择级别“一”中包含“a”的行?

         col
one two     
a   t      0
    u      1
    v      2
    w      3
df.loc[isin(one="a")]

此外,我如何才能在输出中删除级别“一”?

     col
two     
t      0
u      1
v      2
w      3

好吧,那就放下它吧。

df.loc[isin(one="a")].droplevel("one")

问题 1b

如何在级别“two”上切分值为“t”的所有行?

         col
one two     
a   t      0
b   t      4
    t      8
d   t     12
df.loc[isin(two="t")]

这要干净得多。


第2项质询

如何选择与级别“一”中的“b”和“d”项相对应的行?

         col
one two     
b   t      4
    u      5
    v      6
    w      7
    t      8
d   w     11
    t     12
    u     13
    v     14
    w     15

使用 loc,通过指定列表以类似的方式完成此操作。

df.loc[isin(one=["b", "d"])]

问题 2b

如何获得级别“two”中对应于“t”和“w”的所有值?

         col
one two     
a   t      0
    w      3
b   t      4
    w      7
    t      8
d   w     11
    t     12
    w     15
df.loc[isin(two=["t", "w"])] 

第3项质询

如何检索横截面,即具有特定值的单行 对于来自 ?具体来说,我该如何取回十字架 部分 ,由下式给出df('c', 'u')

         col
one two     
c   u      9
df.loc[isin(one="c", two="u")]

第4项质询

如何选择对应于 和 的两行?('c', 'u')('a', 'w')

         col
one two     
c   u      9
a   w      3

由于假设不同级别之间的 and 和不同值之间以及 or 之间的 or,因此直观的解决方案:isin

df.loc[isin(one=["c", "a"], two=["u", "w"])]

也会选择您可能不想要的,但您可以轻松地组合选择器:("c", "w")

df.loc[isin(one="c", two="u") | isin(one="a", two="w")]

或者,如果您有它们的列表,请使用semijoin

from pandas_indexing import semijoin
semijoin(df, pd.MultiIndex.from_tuples([("c", "u"), ("a", "w")], names=["one", "two"]))

第5项质询

如何检索级别“一”中与“a”对应的所有行或 “二”级中的“t”?

         col
one two     
a   t      0
    u      1
    v      2
    w      3
b   t      4
    t      8
d   t     12
df.loc[isin(one="a") | isin(two="t")]

第6项质询

如何对特定的横截面进行切片?对于“a”和“b”,我想选择所有具有子级别“u”和“v”的行,并且 对于“d”,我想选择子级别为“w”的行。

         col
one two     
a   u      1
    v      2
b   u      5
    v      6
d   w     11
    w     15
df.loc[isin(one=["a", "b"], two=["u", "v"]) | isin(one="d", two="w")]

第7项质询

如何获取级别“two”中的值大于 5 的所有行?

         col
one two     
b   7      4
    9      5
c   7     10
d   6     11
    8     12
    8     13
    6     15

从版本 0.2.6 开始:

df2.loc[isin(two=lambda s: s > 5)]