使用多级索引 df(pandas)进行布尔索引

3
我有一个MultiIndex数据框,我想根据我的列和最外层索引级别中的值范围进行索引。例如,对于下面的示例,我尝试选择索引为“l2”的v2中的值,其中v1>12
我可以使用多个索引语句来实现这一点,例如:df[df.v1>12].loc['l2', 'v2'],但这似乎不是很理想。是否有一种方法将其压缩为单个语句?
我一直在尝试弄清如何使用pd.IndexSlice,但似乎无法理解文档中MultiIndex部分的示例在做什么。
df = pd.concat([pd.DataFrame({'v1': range(10, 15), 'v2':range(5, 0, -1)}) 
                for i in range(2)], keys=['l1', 'l2'])

      v1  v2
l1 0  10   5
   1  11   4
   2  12   3
   3  13   2
   4  14   1
l2 0  10   5
   1  11   4
   2  12   3
   3  13   2
   4  14   1

请在同一段代码示例中不要使用像字符串'l2'和整数12这样的值。 - undefined
1个回答

2
你可以使用 切片器 进行选择,然后使用 loc 修改 布尔索引 以选择列 v2
idx = pd.IndexSlice
df1 = df.loc[idx['l2', :], :]
print (df1)
      v1  v2
l2 0  10   5
   1  11   4
   2  12   3
   3  13   2
   4  14   1

print (df1.loc[df1.v1 > 12, 'v2'])
l2  3    2
    4    1
Name: v2, dtype: int32

另一种解决方案,使用xs
df1 = df.xs('l2')
print (df1)
   v1  v2
0  10   5
1  11   4
2  12   3
3  13   2
4  14   1

print (df1.loc[df1.v1 > 12, 'v2'])
3    2
4    1
Name: v2, dtype: int32

df1 = df.xs('l2', drop_level=False)
print (df1)
      v1  v2
l2 0  10   5
   1  11   4
   2  12   3
   3  13   2
   4  14   1

print (df1.loc[df1.v1 > 12, 'v2'])
l2  3    2
    4    1
Name: v2, dtype: int32

使用 get_level_values 选择索引的第一级,如果需要删除第一级,则使用 droplevelreset_index

df1 = df.loc[(df.v1 > 12) & (df.index.get_level_values(0) == 'l2'), 'v2']
df1.index = df1.index.droplevel(0)
#df1 = df1.reset_index(level=0, drop=True)
print (df1)
3    2
4    1
Name: v2, dtype: int32

使用IndexSlice示例:

选择第一层和第二层中从13的所有值(感谢piRSquared):

idx = pd.IndexSlice
print (df.loc[idx[:, 1:3], :])
      v1  v2
l1 1  11   4
   2  12   3
   3  13   2
l2 1  11   4
   2  12   3
   3  13   2

@piRSquared - 谢谢你。 - undefined
感谢详细的回复。我想我的真正问题是是否有一种方法可以在不必将多个索引传递到数据框的不同部分的情况下实现这一点。除了使用get_level_values,我认为这种方式有些笨拙之外,答案似乎是我已经采取的方式没有更简洁的方法。 - undefined
是的,你说得对。使用布尔索引和按索引选择一起是不可能的。如果查看食谱,有一个类似的示例[29] - 使用掩码按列选择并带有索引掩码。祝你有愉快的一天,好运。 - undefined

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