在索引为MultiIndex的数据框架中选择/过滤行最常见的熊猫方法是什么?

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

简单的假设:

输入数据帧没有重复的索引键 下面的输入数据帧只有两层。(这里显示的大多数解都泛化到N层)


示例输入:

mux = pd.MultiIndex.from_arrays [ 列表(“aaaabbbbbccddddd”), 列表(“tuvwtuvwtuvwtuvw”) , names=['one', 'two']) Df = pd。DataFrame({'col': np.arange(len(mux))}, mux) 上校 一个两个 at0 你1 v 2 w 3 B t 4 你5 v 6 w 7 t 8 C u 9 v 10 D w 11 t 12 你13 v 14 w 15

问题1:选择单一项目

我如何选择行有“a”级别“一”?

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

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

     col
two     
t      0
u      1
v      2
w      3

问题1 b 我如何在级别“2”上切片所有值为“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

问题2 b 我如何在“第二层”中获得与“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

Question 7 will use a unique setup consisting of a numeric level: 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:在多索引的各个层次上使用数值不等式进行过滤

我如何获得级别“2”中值大于5的所有行?

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

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


当前回答

我一直在使用这个问题,并很欣赏@cs95的回答,它非常全面,处理了所有实例。类似于@r-a的答案,我也想找到一种方法来处理包含多个级别的多个索引。

我最终找到了一种方法来获得给定级别或指定索引的任意数量的切片,这能够处理上面提出的几个问题。这里的主要改进是不必用pd解析slice(None)或:。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-a指出的,问题在于没有命名索引。有很多方法可以使用这里的方法来满足这一点,例如df.index.names = ["names", "for", "the", " indexes "]或一些类似的方法:

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']

其他回答

这看起来是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

最近,我遇到了一个用例,我有一个3级以上的多索引数据框架,在这个用例中,我不能让上面的任何解决方案产生我想要的结果。上面的解决方案很可能对我的用例有效,我尝试了几个,但我无法在我可用的时间内让它们工作。

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

这是一种不同的方法,可以得到与上面的问题6略有不同的结果。(可能还有其他问题)

我特别想找的是:

从索引的一个级别选择两个+值,从索引的另一个级别选择一个值的方法 在数据帧输出中保留前一个操作的索引值的方法。

就像齿轮上的活动扳手一样(尽管完全可以固定):

这些索引未具名。

在下面的玩具数据框架上:

    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

上面的方法可能有点笨拙,但我发现它满足了我的需求,而且对我来说更容易理解和阅读。

一个选项是使用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

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

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

问题1 b 我如何在级别“2”上切片所有值为“t”的行? 上校 一个两个 at0 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”项对应的行? 上校 一个两个 B t 4 你5 v 6 w 7 t 8 D w 11 t 12 你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

问题2 b 我如何在“第二层”中获得与“t”和“w”对应的所有值? 上校 一个两个 at0 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')的分段,由 上校 一个两个 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')的两行? 上校 一个两个 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" ? 上校 一个两个 at0 你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”的行。 上校 一个两个 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 我如何获得级别“2”中值大于5的所有行? 上校 一个两个 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

试着回答:

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

我一直在使用这个问题,并很欣赏@cs95的回答,它非常全面,处理了所有实例。类似于@r-a的答案,我也想找到一种方法来处理包含多个级别的多个索引。

我最终找到了一种方法来获得给定级别或指定索引的任意数量的切片,这能够处理上面提出的几个问题。这里的主要改进是不必用pd解析slice(None)或:。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-a指出的,问题在于没有命名索引。有很多方法可以使用这里的方法来满足这一点,例如df.index.names = ["names", "for", "the", " indexes "]或一些类似的方法:

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']

多索引/高级索引

Note This post will be structured in the following manner: The questions put forth in the OP will be addressed, one by one For each question, one or more methods applicable to solving this problem and getting the expected result will be demonstrated. Notes (much like this one) will be included for readers interested in learning about additional functionality, implementation details, and other info cursory to the topic at hand. These notes have been compiled through scouring the docs and uncovering various obscure features, and from my own (admittedly limited) experience. All code samples have created and tested on pandas v0.23.4, python3.7. If something is not clear, or factually incorrect, or if you did not find a solution applicable to your use case, please feel free to suggest an edit, request clarification in the comments, or open a new question, ....as applicable.

下面介绍一些我们以后会经常用到的常用成语(以下简称“四大成语”)

DataFrame.loc - A general solution for selection by label (+ pd.IndexSlice for more complex applications involving slices) DataFrame.xs - Extract a particular cross section from a Series/DataFrame. DataFrame.query - Specify slicing and/or filtering operations dynamically (i.e., as an expression that is evaluated dynamically. Is more applicable to some scenarios than others. Also see this section of the docs for querying on MultiIndexes. Boolean indexing with a mask generated using MultiIndex.get_level_values (often in conjunction with Index.isin, especially when filtering with multiple values). This is also quite useful in some circumstances.

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


问题1 我如何选择行有“a”级别“一”? 上校 一个两个 at0 你1 v 2 w 3

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

df.loc[['a']]

此时,如果你得到

TypeError: Expected tuple, got str

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

或者,你可以在这里使用xs,因为我们提取的是单个横截面。注意级别和轴参数(这里可以假设合理的默认值)。

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

在这里,drop_level=False参数是为了防止xs在结果中删除级别“1”(我们所切割的级别)。

这里的另一个选项是使用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']

此外,我如何能够在输出中删除级别“1”? 上校 两个 t 0 你1 v 2 w 3

这可以很容易地使用任何一个

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

Or,

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

注意,我们可以省略drop_level参数(默认情况下它被假设为True)。

Note You may notice that a filtered DataFrame may still have all the levels, even if they do not show when printing the DataFrame out. For example, 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']) You can get rid of these levels using MultiIndex.remove_unused_levels: v.index = v.index.remove_unused_levels()

打印(v.index) MultiIndex(level =[['a'], ['t', 'u', 'v', 'w']], 标签=[[0,0,0,0],[0,1,2,3]], 名称=['一',' 2 '])


问题1 b 我如何在级别“2”上切片所有值为“t”的行? 上校 一个两个 at0 B t 4 t 8 D t 12

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

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

它就是有用!™但它是笨拙的。我们可以使用pd来实现更自然的切片语法。这里是IndexSlice API。

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

这个干净多了。

Note Why is the trailing slice : across the columns required? This is because, loc can be used to select and slice along both axes (axis=0 or axis=1). Without explicitly making it clear which axis the slicing is to be done on, the operation becomes ambiguous. See the big red box in the documentation on slicing. If you want to remove any shade of ambiguity, loc accepts an axis parameter: df.loc(axis=0)[pd.IndexSlice[:, 't']] Without the axis parameter (i.e., just by doing df.loc[pd.IndexSlice[:, 't']]), slicing is assumed to be on the columns, and a KeyError will be raised in this circumstance. This is documented in slicers. For the purpose of this post, however, we will explicitly specify all axes.

对于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”项对应的行? 上校 一个两个 B t 4 你5 v 6 w 7 t 8 D w 11 t 12 你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')

请注意 是的,默认的解析器是'pandas',但重要的是要强调这种语法不是常规的python。的 Pandas解析器生成的解析树与 表达式。这样做是为了使一些操作更加直观 指定。更多信息,请阅读我的帖子 使用pd.eval()在pandas中的动态表达式求值。

并且,get_level_values + Index.isin:

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

问题2 b 我如何在“第二层”中获得与“t”和“w”对应的所有值? 上校 一个两个 at0 w 3 B t 4 w 7 t 8 D w 11 t 12 w 15

对于loc,这只能与pd.IndexSlice结合使用。

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

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

对于查询,这是

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_values和Index。Isin(类似于上面):

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

问题3 我如何检索一个横截面,即,有特定值的单行 对于df的下标?具体来说,我如何找回十字架 ('c', 'u')的分段,由 上校 一个两个 C u 9

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

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

Or,

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

Note At this point, you may run into a PerformanceWarning that looks like this: PerformanceWarning: indexing past lexsort depth may impact performance. This just means that your index is not sorted. pandas depends on the index being sorted (in this case, lexicographically, since we are dealing with string values) for optimal search and retrieval. A quick fix would be to sort your DataFrame in advance using DataFrame.sort_index. This is especially desirable from a performance standpoint if you plan on doing multiple such queries in tandem: df_sort = df.sort_index() df_sort.loc[('c', 'u')] You can also use MultiIndex.is_lexsorted() to check whether the index is sorted or not. This function returns True or False accordingly. You can call this function to determine whether an additional sorting step is required or not.

对于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')的两行? 上校 一个两个 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" ? 上校 一个两个 at0 你1 v 2 w 3 B t 4 t 8 D t 12

这实际上很难用loc做到,同时确保正确性并保持代码清晰。df.loc [pd。IndexSlice['a', 't']]不正确,它被解释为df.loc[pd. loc]。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”的行。 上校 一个两个 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”及其子级别进行切片是有模式的,所以我们可以将切片任务分成两部分并连接结果:

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

“a”和“b”的切片规范稍微干净一些(('a', 'b'), ('u', 'v')),因为每个层被索引的相同子层是相同的。


问题7 我如何获得级别“2”中值大于5的所有行? 上校 一个两个 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]

请注意 与此示例类似,我们可以使用这些构造基于任意条件进行筛选。一般来说,记住loc和xs是专门用于基于标签的索引,而查询和 Get_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

您需要对四个成语进行以下更改,以使它们与列一起工作。

To slice with loc, use df3.loc[:, ....] # Notice how we slice across the index with `:`. or, df3.loc[:, pd.IndexSlice[...]] To use xs as appropriate, just pass an argument axis=1. You can access the column level values directly using df.columns.get_level_values. You will then need to do something like df.loc[:, {condition}] Where {condition} represents some condition built using columns.get_level_values. To use query, your only option is to transpose, query on the index, and transpose again: df3.T.query(...).T Not recommended, use one of the other 3 options.