如何构建以原列为顶层、含计算列的多级索引Pandas DataFrame?
问题描述
现有输入DataFrame如下:
index | col_1 | col_2 | 1 | 1234 | 4567 | 2 | 3456 | 9453 |
该DataFrame的每一列均为时间序列,需对每列执行计算生成等长序列(例如计算最近5个样本的滑动均值opr_1、最近10个样本的滑动均值opr_2),最终输出需按原列名分组,结构如下:
Output: | col_1 | col_2 | index | value opr_1 opr_2 | value opr_1 opr_2 | 1 | 1234 10 1 | 4567 22 13 | 2 | 3456 18 6 | 9453 21 4 |
要求可通过df['col_1']['value']这类方式访问原列及其相关计算结果。
尝试过两种方案但均遇问题:
- 手动提升索引层级:
df.columns = pd.MultiIndex.from_product([df.columns, ['value']])
无法仅对第二层执行apply操作,也不知道如何将计算结果存入df['col_1']['opr_1']层级中。
2. 为每个计算生成单独的DataFrame:
opr_1 = df.apply(lambda x: opr_1_func(x, **params)) opr_2 = df.apply(lambda x: opr_2_func(x, **params))
不知如何拼接这三个DataFrame以得到目标多级索引结构。
解决方案
要实现目标的多级索引结构,可通过构造带多级索引列的DataFrame并横向拼接完成,具体步骤如下:
1. 转换原始数据为多级索引列
先将原始DataFrame的列重构为(原列名, 'value')的多级索引形式,保留原始值:
df_raw = df.copy() # 生成(列名, 'value')的元组作为多级列名 df_raw.columns = pd.MultiIndex.from_tuples([(col, 'value') for col in df_raw.columns])
2. 为计算结果添加对应多级索引
对每个操作生成结果后,为结果列赋予(原列名, 操作名)的多级索引,确保后续拼接时能对应到正确的原列下:
# 生成opr_1计算结果,设置多级列名 opr_1 = df.apply(lambda x: opr_1_func(x, **params)) opr_1.columns = pd.MultiIndex.from_tuples([(col, 'opr_1') for col in opr_1.columns]) # 生成opr_2计算结果,设置多级列名 opr_2 = df.apply(lambda x: opr_2_func(x, **params)) opr_2.columns = pd.MultiIndex.from_tuples([(col, 'opr_2') for col in opr_2.columns])
3. 拼接所有DataFrame并整理结构
使用pd.concat横向拼接原始数据和两个计算结果的DataFrame,再按一级列名排序,保证同一原列的子列(value、opr_1、opr_2)排列在一起:
result = pd.concat([df_raw, opr_1, opr_2], axis=1) # 按一级列名排序,规整结构 result = result.sort_index(axis=1, level=0)
完成后,即可通过result['col_1']['value']、result['col_1']['opr_1']这类方式直接访问对应数据,完全匹配需求。
替代方案:逐列构造再合并
如果觉得上述步骤不够直观,也可以遍历每个原列,单独构造该列的所有子列后再合并:
result_dfs = [] for col in df.columns: # 提取原始值并设置多级索引名 value_series = df[col].rename((col, 'value')) # 计算opr_1并设置索引名 opr1_series = opr_1_func(df[col], **params).rename((col, 'opr_1')) # 计算opr_2并设置索引名 opr2_series = opr_2_func(df[col], **params).rename((col, 'opr_2')) # 拼接当前列的所有子列 col_df = pd.concat([value_series, opr1_series, opr2_series], axis=1) result_dfs.append(col_df) # 合并所有列的DataFrame result = pd.concat(result_dfs, axis=1)
这种方式逻辑更清晰,也能严格保证每列的子列顺序符合预期。
内容的提问来源于stack exchange,提问作者Anshul
相关产品推荐
相关产品推荐

