1 回答
TA贡献1786条经验 获得超11个赞
多重索引/高级索引
注
该员额的结构如下:
执行部分中提出的问题将一个接一个地加以解决。 对于每个问题,将演示一个或多个用于解决该问题并获得预期结果的方法。 注
对于有兴趣了解更多功能、实现细节和其他相关信息的读者,将包括S(与此类似)。这些注释是通过浏览文档和发现各种晦涩的特性,并根据我自己(无可否认是有限的)经验编写的。
所有代码示例都在 熊猫v0.23.4,python3.7..如果某些事情不清楚,或者实际上不正确,或者如果您没有找到适用于您的用例的解决方案,请随时建议编辑,在评论中要求澄清,或在适用的情况下打开一个新的问题。
DataFrame.loc
-标签选择的一般解决方案(+) pd.IndexSlice
对于涉及片的更复杂的应用程序) DataFrame.xs
-从系列/DataFrame中提取特定的截面。 DataFrame.query
-动态指定切片和/或过滤操作(即,作为动态计算的表达式。比其他情况更适用于某些情况。亦见 这部分文档 用于查询多个索引。 使用 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
df.loc[('a', slice(None)), :]
.
xs
levels
axis
df.xs('a', level=0, axis=0, drop_level=False)# df.xs('a', drop_level=False)
drop_level=False
xs
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 0u 1v 2w 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_level
True
注
您可能会注意到,过滤后的DataFrame可能仍然具有所有级别,即使它们在打印出DataFrame时没有显示出来。例如, v = df.loc[['a']]print(v) col one two a t 0 u 1 v 2 w 3print(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
如何将值为“t”的所有行分割为“二级”? col one two a t 0b t 4 t 8d t 12
slice()
:
df.loc[(slice(None), 't'), :]
pd.IndexSlice
idx = pd.IndexSlicedf.loc[idx[:, 't'], :]
注
为什么尾翼 :
纵横交错?这是因为 loc
可用于沿两个轴( axis=0
或 axis=1
)。如果不明确说明要在哪个轴上进行切片,操作就变得模糊不清。看到那个红色的大盒子 切片文件 .
如果你想消除任何含糊不清的地方, loc
接受 axis
参数: df.loc(axis=0)[pd.IndexSlice[:, 't']]
没有 axis
参数(即,只需执行 df.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 8d w 11 t 12 u 13 v 14 w 15
df.loc[['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.val() .
get_level_values
+ Index.isin
:
df[df.index.get_level_values("one").isin(['b', 'd'])]
问题2b
如何得到“二级”中与“t”和“w”对应的所有值? col one two a t 0 w 3b t 4 w 7 t 8d w 11 t 12 w 15
loc
pd.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_values
Index.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.
这只意味着索引没有排序。熊猫取决于被排序的索引(在这种情况下,按字典顺序,因为我们处理的是字符串值),以便进行最佳搜索和检索。一个快速的解决方法是预先使用以下方法对DataFrame进行排序 DataFrame.sort_index
..如果您计划同时执行多个这样的查询,那么从性能的角度来看,这是特别可取的: df_sort = df.sort_index()df_sort.loc[('c', 'u')]
您也可以使用 MultiIndex.is_lexsorted()
若要检查索引是否已排序,请执行以下操作。此函数返回 True
或 False
因此。您可以调用此函数来确定是否需要额外的排序步骤。
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 9a 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)
问题5
如何检索与“一级”中的“a”或“二级”中的“t”对应的所有行? col one two a t 0 u 1 v 2 w 3b t 4 t 8d t 12
loc
df.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 8d t 12
v = pd.concat([ df.loc[['a'],:], df.loc[pd.IndexSlice[:, 't'],:]])v[~v.index.duplicated()]
query
df.query("one == 'a' or two == 't'")
get_level_values
m1 = (df.index.get_level_values('one') == 'c')m2 = (df.index.get_level_values('two') == 'u')df[m1 | m2]
问题6
如何分割特定的截面?对于“a”和“b”,我想选择所有具有子级别“u”和“v”的行,对于“d”,我想选择具有子级别“w”的行。 col one two a u 1 v 2b u 5 v 6d w 11 w 15
loc
keys = [('a', 'u'), ('a', 'v'), ('b', 'u'), ('b', 'v'), ('d', 'w')]df.loc[keys, :]
concat
pd.concat([ df.loc[(('a', 'b'), ('u', 'v')), :], df.loc[('d', 'w'), :] ], axis=0)
(('a', 'b'), ('u', 'v'))
问题7
如何获得级别“2”中的值大于5的所有行? col one two b 7 4 9 5c 7 10d 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
专门用于基于标签的索引,而 query
和 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 h0 5 0 3 3 7 9 3 5 2 4 7 6 8 8 1 61 7 7 8 1 5 9 8 9 4 3 0 3 5 0 2 32 8 1 3 3 3 7 0 1 9 9 0 4 7 3 2 7
切成片 loc
,使用 df3.loc[:, ....] # Notice how we slice across the index with `:`.
或, df3.loc[:, pd.IndexSlice[...]]
使用 xs
在适当的情况下,只需传递一个参数。 axis=1
.可以直接访问列级别的值。 df.columns.get_level_values
..然后你需要做一些类似的事情 df.loc[:, {condition}]
哪里 {condition}
表示使用 columns.get_level_values
.使用 query
,您的唯一选项是转置,查询索引,然后再次转置: df3.T.query(...).T
不建议使用其他3种选项之一。
添加回答
举报