Python 如何使用另一个多索引的多索引对一个多索引数据帧进行切片

Python 如何使用另一个多索引的多索引对一个多索引数据帧进行切片,python,pandas,dataframe,multi-index,Python,Pandas,Dataframe,Multi Index,我有一个熊猫数据框架,它有三层多重索引。我试图根据对应于两个级别的值列表从这个数据帧中取出行 我有这样的想法: ix = pd.MultiIndex.from_product([[1, 2, 3], ['foo', 'bar'], ['baz', 'can']], names=['a', 'b', 'c']) data = np.arange(len(ix)) df = pd.DataFrame(data, index=ix, columns=['hi']) print(df)

我有一个熊猫数据框架,它有三层多重索引。我试图根据对应于两个级别的值列表从这个数据帧中取出行

我有这样的想法:

ix = pd.MultiIndex.from_product([[1, 2, 3], ['foo', 'bar'], ['baz', 'can']], names=['a', 'b', 'c'])
data = np.arange(len(ix))
df = pd.DataFrame(data, index=ix, columns=['hi'])
print(df)

           hi
a b   c      
1 foo baz   0
      can   1
  bar baz   2
      can   3
2 foo baz   4
      can   5
  bar baz   6
      can   7
3 foo baz   8
      can   9
  bar baz  10
      can  11
现在我想取索引级别“b”和“c”在此索引中的所有行:

ix_use = pd.MultiIndex.from_tuples([('foo', 'can'), ('bar', 'baz')], names=['b', 'c'])
i、 e.
hi
具有
('foo','can')
('bar','baz')
的值分别位于
b
c
级别:
(1,2,5,6,9,10)

因此,我想在第一层上取一个
切片(None)
,在第二层和第三层上提取特定的元组


起初,我认为将多索引对象传递给.loc会提取出我想要的值/级别,但这不起作用。这样做的最佳方法是什么?

以下是获取此切片的方法:

df.sort_index(inplace=True)
idx = pd.IndexSlice
df.loc[idx[:, ('foo','bar'), 'can'], :]
屈服

           hi
a b   c      
1 bar can   3
  foo can   1
2 bar can   7
  foo can   5
3 bar can  11
  foo can   9
请注意,您可能需要对多索引进行排序,然后才能对其进行切片。如果你需要的话,熊猫会提醒你:

KeyError: 'MultiIndex Slicing requires the index to be fully lexsorted tuple len (3), lexsort depth (1)'
cond1 = (df.index.get_level_values('b').isin(['foo'])) & (df.index.get_level_values('c').isin(['can']))
cond2 = (df.index.get_level_values('b').isin(['bar'])) & (df.index.get_level_values('c').isin(['baz']))
df[cond1 | cond2]
您可以在中阅读有关如何使用切片器的更多信息

如果出于某种原因,无法使用切片器,则可以使用
.isin()
方法获取相同的切片:

df[df.index.get_level_values('b').isin(ix_use.get_level_values(0)) & df.index.get_level_values('c').isin(ix_use.get_level_values(1))]
这显然不够简洁

更新:

对于您已更新的条件,这里有一种方法:

KeyError: 'MultiIndex Slicing requires the index to be fully lexsorted tuple len (3), lexsort depth (1)'
cond1 = (df.index.get_level_values('b').isin(['foo'])) & (df.index.get_level_values('c').isin(['can']))
cond2 = (df.index.get_level_values('b').isin(['bar'])) & (df.index.get_level_values('c').isin(['baz']))
df[cond1 | cond2]
制作:

           hi
a b   c      
1 foo can   1
  bar baz   2
2 foo can   5
  bar baz   6
3 foo can   9
  bar baz  10

我发现这不起作用很有趣:

In [45]: df.loc[(idx[:, 'foo', 'can'], idx[:, 'bar', 'baz']), ]
Out[45]: 
           hi
a b   c      
1 bar baz   2
      can   3
  foo baz   0
      can   1
2 bar baz   6
      can   7
  foo baz   4
      can   5
3 bar baz  10
      can  11
  foo baz   8
      can   9
不知何故,这看起来似乎是“应该”的。无论如何,这里有一个合理的解决办法:

让我们假设要切片的元组位于另一个
数据帧的索引中(因为听起来它们可能在您的情况下!)

现在通过
other
的索引对
df
进行切片,我们可以利用
.loc
/
.ix
允许您给出元组列表的事实(参见最后一个示例)

首先,让我们构建我们想要的元组列表:

In [13]: idx = [(x, ) + y for x in df.index.levels[0] for y in other.index.values]
In [14]: idx
Out[14]: 
[(1, 'foo', 'can'),
 (1, 'bar', 'baz'),
 (2, 'foo', 'can'),
 (2, 'bar', 'baz'),
 (3, 'foo', 'can'),
 (3, 'bar', 'baz')]
现在我们可以将此列表传递到
.ix
.loc

In [17]: df.ix[idx]
Out[17]: 
           hi
a b   c      
1 foo can   1
  bar baz   2
2 foo can   5
  bar baz   6
3 foo can   9
  bar baz  10
我想推荐一种类似的

简单地说,我认为这是一种更自然的表达方式:

In [27]: df.query("(b == 'foo' and c == 'can') or (b == 'bar' and c == 'baz')")
Out[27]: 
           hi
a b   c      
1 foo can   1
  bar baz   2
2 foo can   5
  bar baz   6
3 foo can   9
  bar baz  10

这真的很接近我想要的,但我应该更清楚地表达这个问题。实际上,我需要的是来自级别“c”的值,它依赖于级别“b”中的值。例如,每当b级为“foo”时,我想要c级为“can”时的值,每当b级为“bar”时,我想要c级为“baz”时的值用这两个条件更新答案,这应该给出一个如何处理这个问题的想法。我有过几次不同的尝试来实现这一点。我想我已经找到了一个不错的解决办法,来解决目前看来有点难的问题。试试看!