对于索引为MultiIndex的 Dataframe ,选择/筛选行的最常用方法是什么?
- 基于单个值/标签的切片
- 基于一个或多个级别的多个标注进行切片
- 筛选布尔条件和表达式
- 哪些方法适用于哪些情况
简化假设:
1.输入 Dataframe 没有重复的索引键
1.下面的输入 Dataframe 只有两个级别。(此处显示的大多数解决方案一般化为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
此外,我如何能够在输出中删除级别“1”?
col
two
t 0
u 1
v 2
w 3
问题1b
如何对级别“2”上值为“t”的所有行进行切片?
col
one two
a t 0
b t 4
t 8
d t 12
问题2:在一个级别中选择多个值
如何选择与级别“one”中的项目“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
如何获得与级别“2”中的“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:每层分割一个项目
如何检索与级别“1”中的“a”或级别“2”中的“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:按多索引的各个级别上的数值不等式进行筛选
如何获取级别“2”中的值大于5的所有行?
col
one two
b 7 4
9 5
c 7 10
d 6 11
8 12
8 13
6 15
注意:这篇文章不会讨论如何创建多索引,如何对它们执行赋值操作,或者任何与性能相关的讨论(这些是另一个单独的主题)。
5条答案
按热度按时间2uluyalo1#
多重索引/进阶索引
备注
该员额的结构如下:
1.对于每个问题,将演示一种或多种适用于解决该问题并获得预期结果的方法。
Notes(很像这篇文章)是为有兴趣了解附加功能、实现细节和其他粗略信息的读者准备的。这些注解是通过搜索文档和发现各种晦涩的特性以及我自己的经验(承认有限)编写的。
所有代码示例均已在pandas v0. 23. 4,python3. 7上创建和测试。如果有不清楚的地方,或事实上不正确,或如果您没有找到适用于您的用例的解决方案,请随时建议编辑,在评论中要求澄清,或打开一个新的问题,....如适用。
下面介绍一些常见的成语(以下简称四大成语),我们将经常重温
1.*
DataFrame.loc
* -按标签选择的一般解决方案(+ *pd.IndexSlice
* 适用于涉及切片的更复杂应用程序)1.*
DataFrame.xs
* -从Series/DataFrame中提取特定横截面。1.*
DataFrame.query
* -动态指定切片和/或筛选操作(即,作为动态计算的表达式)。这比其他情况更适用于某些情况。有关MultiIndexes上的查询,另请参阅文档的这一节。1.使用 *
MultiIndex.get_level_values
* 生成掩码的布尔索引(通常与 *Index.isin
* 结合使用,特别是在使用多个值进行筛选时)。这在某些情况下也非常有用。从四个成语的Angular 来看待各种切片和过滤问题,对更好地理解什么可以应用于特定的情况是有益的。理解不是所有的成语都能同样好地工作是非常重要的如果一个习语没有被列为解决问题的潜在方法,这意味着习语不能有效地应用于那个问题。
问题1
如何选择级别“一”中包含“a”的行?
您可以使用
loc
作为适用于大多数情况的通用解决方案:在这一点上,如果你得到
这意味着您使用的是旧版的panda。请考虑升级!否则,请使用
df.loc[('a', slice(None)), :]
。或者,您可以在此处使用
xs
,因为我们提取的是单个横截面。注意levels
和axis
参数(此处可以假定合理的默认值)。这里,需要
drop_level=False
参数来防止xs
在结果中丢弃级别“1”(我们切片的级别)。这里还有另一个选项是使用
query
:如果索引没有名称,则需要将查询字符串更改为
"ilevel_0 == 'a'"
。最后,使用
get_level_values
:此外,我如何能够在输出中删除级别“1”?
这可以通过以下任一方法 * 轻松 * 完成
或者,
请注意,我们可以省略
drop_level
参数(默认情况下假定为True
)。备注
您可能会注意到,经过筛选的DataFrame可能仍然具有所有级别,即使在输出DataFrame时这些级别没有显示。例如,
您可以使用
MultiIndex.remove_unused_levels
摆脱这些级别:一个
问题1b
如何对级别“2”上值为“t”的所有行进行切片?
直觉上,您会想要包含 *
slice()
* 的项目:但是它很笨拙。我们可以在这里使用
pd.IndexSlice
API来简化一个更自然的切片语法。这里干净多了。
备注
为什么需要跨列的尾部切片
:
?这是因为,loc
可以用于选择并沿着两个轴(axis=0
或axis=1
)切片。如果不明确说明切片将在哪个轴上进行,操作将变得不明确。请参阅切片文档中的大红框。如果要消除任何模糊性,
loc
接受axis
参数:如果没有
axis
参数(即,只执行df.loc[pd.IndexSlice[:, 't']]
),则假定切片在列上,并且在这种情况下将引发KeyError
。这在slicers中有详细的说明。然而,为了这篇文章的目的,我们将明确指定所有的轴。
对于
xs
,它是对于
query
,它是型
最后,使用
get_level_values
,您可以都是一样的效果。
问题2
如何选择与级别“one”中的项目“B”和“d”对应的行?
使用loc时,可以通过指定一个列表以类似的方式完成此操作。
存储器
要解决上述选择“b”和“d”的问题,还可以使用
query
:备注
是的,默认的解析器是
'pandas'
,但是需要强调的是,这个语法并不是传统的python语法。Pandas解析器生成的解析树与表达式略有不同。这样做是为了使一些操作更直观地指定。要了解更多信息,请阅读我在Dynamic Expression Evaluation in pandas using pd.eval()上的文章。并且,使用
get_level_values
+Index.isin
:问题2b
如何获得与级别“2”中的“t”和“w”对应的所有值?
对于
loc
,这 * 仅 * 在与pd.IndexSlice
结合使用时才有可能。pd.IndexSlice[:, ['t', 'w']]
中的第一个冒号:
表示切片跨越第一个级别。随着所查询级别的深度增加,您需要指定更多切片,每个切片跨越的级别一个切片。但是,您不需要指定切片 * 之外 * 的更多级别。对于
query
,这是对于
get_level_values
和Index.isin
(与上面类似):问题3
如何从
df
中检索一个横截面,即具有特定索引值的单行?具体来说,如何检索('c', 'u')
的横截面,由下式给出型
通过指定键元组来使用
loc
:型
或者,
备注
此时,您可能会遇到如下所示的 *
PerformanceWarning
*:显示器
这只是意味着您的索引没有排序。panda依赖于索引的排序(在本例中,是按字典顺序排序,因为我们处理的是字符串值),以实现最佳的搜索和检索。一个快速的解决方案是提前使用 *
DataFrame.sort_index
* 对DataFrame进行排序。如果您计划一前一后地执行多个此类查询,从性能的Angular 来看,这是特别理想的:您也可以使用
MultiIndex.is_lexsorted()
来检查索引是否已排序。此函数会传回True
或False
。您可以呼叫此函数来判断是否需要额外的排序步骤。对于
xs
,这也是简单地传递一个元组作为第一个参数,将所有其他参数设置为相应的默认值:使用
query
时,情况变得有点笨拙:型
你现在可以看到,这将是相对困难的概括,但是对于这个特殊的问题仍然是可以的。
对于跨多个级别的访问,仍然可以使用
get_level_values
,但不建议使用:问题4
如何选择与
('c', 'u')
和('a', 'w')
对应的两行?型
对于
loc
,这仍然是简单的:型
对于
query
,您需要通过迭代横截面和级别来动态生成查询字符串:型
100%不推荐!但这是可能的。
如果我有多个级别会怎样?
在这种情况下,一个选项是使用
droplevel
删除您不检查的级别,然后使用isin
测试成员资格,最后对最终结果进行布尔索引。型
问题5
如何检索与级别“1”中的“a”或级别“2”中的“t”对应的所有行?
型
在确保正确性 * 和 * 代码清晰性的同时,使用
loc
实际上很难做到这一点。df.loc[pd.IndexSlice['a', 't']]
是不正确的,它被解释为df.loc[pd.IndexSlice[('a', 't')]]
(即选择一个横截面)。您可以考虑使用pd.concat
的解决方案来分别处理每个标签:显示器
但是您会注意到其中一行是重复的,这是因为该行同时满足了两个切片条件,因此出现了两次。
但是,如果DataFrame本身包含重复的索引(您需要的),则此操作将不会保留它们。使用时要格外小心。
对于
query
,这非常简单:对于
get_level_values
,这仍然很简单,但不那么优雅:问题6
如何对特定的横截面进行切片?对于“a”和“B”,我希望选择子级别为“u”和“v”的所有行,对于“d”,我希望选择子级别为“w”的行。
这是我添加的一个特殊情况,以帮助理解四个习惯用法的适用性-在这个情况下,它们都不会有效地工作,因为切片是 * 非常 * 特定的,并且不遵循任何真实的的模式。
通常,像这样的分片问题需要显式地将一个键列表传递给
loc
。如果你想保存一些输入,你会认识到有一个模式来切片“a”,“B”和它的子级别,所以我们可以把切片任务分成两部分,结果是
concat
:型
“a”和“B”的切片规范
(('a', 'b'), ('u', 'v'))
稍微清晰一些,因为每个级别的索引子级别都相同。问题7
如何获取级别“2”中的值大于5的所有行?
型
这可以使用
query
来完成,型
和
get_level_values
。备注
与这个例子类似,我们可以使用这些结构根据任意条件进行过滤。一般来说,记住
loc
和xs
是专门用于基于标签的索引的,而query
和get_level_values
有助于构建过滤的通用条件掩码。附加问题
如果我需要对
MultiIndex
column 进行切片,该怎么办?实际上,这里的大多数解决方案也适用于列,只是做了一些小的改动。
显示器
以下是您需要对“四个习惯用法”进行的更改,以使它们与列一起使用。
1.要使用
loc
进行切片,请使用或者,
1.要适当地使用
xs
,只需传递参数axis=1
。1.您可以使用
df.columns.get_level_values
直接访问列级别值。其中,
{condition}
表示使用columns.get_level_values
生成的某个条件。1.要使用
query
,唯一的选择是转置、查询索引,然后再次转置:不建议使用,请使用其他3个选项之一。
kkbh8khc2#
最近,我遇到了一个用例,在这个用例中,我有一个3+级别的多索引 Dataframe ,在这个 Dataframe 中,我不能使上面的任何解决方案产生我所寻找的结果。上面的解决方案当然很可能对我的用例有效,我尝试了几个,但是我不能让它们在我可用的时间内工作。
我不是Maven,但我偶然发现了一个解决方案,没有在上面的综合答案中列出。我不保证解决方案在任何方面都是最佳的。
这是一个不同的方式得到一个稍微不同的结果,问题#6以上。(和可能的其他问题,以及)
具体来说,我在寻找:
1.一种从指数的一个级别选择两个+值,从指数的另一个级别选择一个值的方法,以及
1.一种在 Dataframe 输出中保留上一操作的索引值的方法。
作为齿轮中的活动扳手(但完全可以固定):
1.索引未命名。
在下面的玩具数据框中:
当然使用下面的作品:
但是我想要一个不同的结果,所以我得到这个结果的方法是:
如果我想从一个级别得到两个+值,从另一个级别得到一个(或2+)值:
上面的方法可能有点笨重,但我发现它满足了我的需要,作为奖励,我更容易理解和阅读。
wqnecbli3#
这看起来是dfsql的一个很好的案例
https://github.com/mindsdb/dfsql
关于它的完整文章在这里:
https://medium.com/riselab/why-every-data-scientist-using-pandas-needs-modin-bringing-sql-to-dataframes-3b216b29a7c0
wtzytmuj4#
我很喜欢这个问题,@cs95的回答非常全面,可以处理所有的示例。与@r-a的回答类似,我也想找到一种方法来处理包含多个级别的多个索引。
我终于找到了一种方法,可以在给定一个级别或一个命名索引的情况下获得任意数量的切片,这种方法能够处理上面提出的几个问题。这里的主要改进是不必解析出
slice(None)
或带有pd.IndexSlice
的:
来获得多个索引或切片。这样做的好处是,您可以将这些调用的任意组合添加到函数
slice_df_by
中,以获得更复杂的切片,同时只使用索引名称和值列表。正如@r-a所指出的,问题是没有命名索引,有很多方法可以满足这一点,比如
df.index.names = ["names", "for", "the", "indices"]
或类似的方法:bcs8qyzn5#
一个选项是使用select_rows from pyjanitor:
问题1
如何选择级别“一”中包含“a”的行?
此外,我如何能够在输出中删除级别“1”?
问题1b
如何对级别“2”上值为“t”的所有行进行切片?
在此使用字典,指定层级为索引键,并传递标签以选取:
问题2
如何选择与级别“one”中的项目“B”和“d”对应的行?
由于选择在单个级别上,因此传递标签列表:
问题2b
如何获得与级别“2”中的“t”和“w”对应的所有值?
使用字典:
问题3
如何检索一个横截面,即从
df
中检索具有特定索引值的单行?具体来说,如何检索('c', 'u')
的横截面,由下式给出我们将跨级别(水平,而不是垂直)进行操作,需要一个元组:
问题4
如何选择与
('c', 'u')
和('a', 'w')
对应的两行?select_rows
接受多个变量参数:问题5
如何检索与级别“1”中的“a”或级别“2”中的“t”对应的所有行?
第一个
问题6
如何对特定的横截面进行切片?对于“a”和“B”,我希望选择子级别为“u”和“v”的所有行,对于“d”,我希望选择子级别为“w”的行。
第一个
问题7
如何获取级别“2”中的值大于5的所有行?
型
使用字典,您可以传递函数,只要它可以在Index对象上评估:
您可以使用select_columns函数选择列。还有一个通用的select函数可以同时选择行和列。
这些函数是可扩展的:让我们看看@double0darbo是如何工作的答案:
同时尝试@r回答:
存储器