You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将DataFrame转为pandas IndexSlice以索引MultiIndex多层DataFrame

问题描述

我有以下2个DataFrame:df1和df2:

import pandas as pd

m_idx = pd.MultiIndex.from_product([range(3), range(3, 6), range(6, 8)])
m_idx.names = ['a', 'b', 'c']
df1 = pd.DataFrame(None, index=m_idx, columns=['x1', 'x2', 'x3'])
df1.loc[:, 'x1'] = m_idx.get_level_values('a') + m_idx.get_level_values('b') + m_idx.get_level_values('c')
df1.loc[:, 'x2'] = df1.loc[:, 'x1'] * 2
df1.loc[:, 'x3'] = df1.loc[:, 'x1'] * 3

df2 = pd.DataFrame({'a': [0, 2], 'c': [6, 6]})

df1输出示例:

x1  x2  x3
a b c            
0 3 6   9  18  27
    7  10  20  30
  4 6  10  20  30
    7  11  22  33
  5 6  11  22  33
    7  12  24  36
1 3 6  10  20  30
    7  11  22  33
  4 6  11  22  33
    7  12  24  36
  5 6  12  24  36
    7  13  26  39
2 3 6  11  22  33
    7  12  24  36
  4 6  12  24  36
    7  13  26  39
  5 6  13  26  39
    7  14  28  42

df2输出示例:

a  c
0  0  6
1  2  6

df2的列名对应df1的MultiIndex层级名,每一行是我需要从df1中查询的索引键组合。我希望将df2转换为能执行下述逻辑的索引参数:

df1.loc[pd.IndexSlice[[0, 2], :, [6, 6]], :]

上述代码的返回结果如下:

x1  x2  x3
a b c            
0 3 6   9  18  27
  4 6  10  20  30
  5 6  11  22  33
2 3 6  11  22  33
  4 6  12  24  36
  5 6  13  26  39

我此前参考其他方案采用逐行遍历df2再拼接结果的方式实现,代码如下:

df_list = [df1.loc[(v[0], slice(None), v[1]), :] for r, v in df2.iterrows()]
df_sliced = pd.concat(df_list)

但该方法在数据量大时效率过低,无法满足我的需求,因此希望找到使用pd.IndexSlice或其他更高效的替代方案。


解决方案

以下是3种性能远高于逐行遍历的实现方案:

方案1:多层级布尔索引(性能最优推荐)

无需重置索引,直接通过索引层级匹配构造过滤掩码,适合大数据量场景:

# 把df2的行转为元组集合,用于快速匹配
match_keys = set(df2.itertuples(index=False, name=None))
# 去掉不需要筛选的b层级,直接匹配(a,c)组合是否在目标集合内
mask = df1.index.droplevel('b').isin(match_keys)
df_sliced = df1[mask]

方案2:动态生成IndexSlice(适配动态层级场景)

如果需要灵活适配不同的筛选层级,可按索引名自动构造IndexSlice参数,无需手动写死层级顺序:

slice_params = []
for level_name in df1.index.names:
    if level_name in df2.columns:
        # 该层级需要筛选,取df2对应列的去重值作为筛选条件
        slice_params.append(df2[level_name].unique().tolist())
    else:
        # 该层级不需要筛选,保留所有值
        slice_params.append(slice(None))

df_sliced = df1.loc[tuple(slice_params), :]

方案3:merge关联法(逻辑直观易理解)

如果更贴近常规表关联逻辑,写法易懂:

df_sliced = df1.reset_index().merge(df2, on=['a', 'c']).set_index(['a','b','c'])

以上三种方案输出结果均和预期完全一致,数据量越大前两种方案的性能优势越明显,比逐行遍历效率高数十到上百倍。

内容的提问来源于stack exchange,提问作者Arthur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 00:57:02