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

如何为Pandas多级索引DataFrame添加空子列及子子列?

问题背景

我正在使用Pandas处理多级索引的多列DataFrame,包含16个一级列(如Climate Change、Ozone Depletion等),每个一级列下有两个二级子列:Agriculture和Transformation。我想为每个一级列新增一个名为Transport的空二级子列,后续填充数据。

初始尝试的问题

尝试过如下循环代码:

for i in list(df.columns.levels[0]):
    df[i, 'Transport'] = ''

但该操作会重复生成带空值的一级列,无法正确分组。我希望找到无需循环的实现方式;若必须用循环,如何让新创建的列正确归组?

已查看相关问题但未解决需求。

测试代码(补充)

import pandas as pd
import numpy as np

df = pd.DataFrame([[1,2,3,4], [5,6,7,8],[9,10,11,12]], 
                  columns = pd.MultiIndex.from_product([('Acidification', 'Climate Change'), ('Agriculture', 'Transformation')]), 
                  index=['potato', 'tomato', 'onion'])

使用@Laurent的方案并修改一行代码后,得到了预期结果:

dfs = []
for col in df.columns.levels[0]:
    tmp = df.copy()[col]
    tmp.loc[:, ("Transport")] = "" # 修改的行
    dfs.append(tmp)
new_df = pd.concat(dfs, axis=1, keys=df.columns.levels[0])

但我希望有更通用的实现方法。


问题1

现在我想为所有一级列下的Transport二级子列新增两个三级子列(National和Import),该如何实现?尝试如下代码时出现unhashable type: 'slice'错误:

# 尝试沿用之前的逻辑
dfn = []
for col in new_df.columns.levels[0]:
    for scol in new_df.columns.levels[1]:
        tmp = new_df.copy()[col][scol]
        tmp.loc[:, ('National')] = ""
        tmp.loc[:, ('Import')] = ""
        dfn.append(tmp)
new_dfn = pd.concat(dfn, axis=1, keys=new_df.columns.levels[0])

问题2

是否存在通用方法,可为所有列中的指定子列添加新的子子列?


解决方案

一、无需循环添加二级子列Transport

直接通过重构多级索引列实现,避免循环和列混乱:

# 获取原有一级列集合,将Transport加入二级列集合
level0 = df.columns.levels[0]
level1 = df.columns.levels[1].union(['Transport'])

# 生成新的多级列索引
new_columns = pd.MultiIndex.from_product([level0, level1])

# 重新索引DataFrame,新增列自动填充空字符串
new_df = df.reindex(columns=new_columns).fillna('')

这种方法会自动将Transport列归属于对应一级列下,不会出现重复列问题。

二、为Transport添加三级子列National和Import

方法1:分步构造三级索引

针对问题1的错误,核心是正确处理三级索引的元组构造:

# 整理所有列的元组列表,为Transport扩展三级子列
existing_cols = []
for col in new_df.columns:
    if col[1] != 'Transport':
        # 非Transport列补充空三级层,保持层级统一
        existing_cols.append((col[0], col[1], ''))
    else:
        # 为Transport添加两个三级子列
        existing_cols.extend([(col[0], col[1], 'National'), (col[0], col[1], 'Import')])

# 转换为三级MultiIndex
new_columns_3lvl = pd.MultiIndex.from_tuples(existing_cols, names=['Level0', 'Level1', 'Level2'])

# 重新索引并填充空值
new_dfn = new_df.reindex(columns=new_columns_3lvl, level=[0,1]).fillna('')

方法2:通用多级列扩展函数

针对问题2,编写通用函数实现任意层级的子列扩展:

def add_subcols_to_multilevel(df, target_level, target_subcol, new_subcols, fill_value=''):
    """
    为多级索引DataFrame的指定子列添加新的子子列
    参数:
        df: 原多级索引DataFrame
        target_level: 目标子列所在层级(从0开始计数)
        target_subcol: 要扩展的目标子列名称
        new_subcols: 新增的子子列列表
        fill_value: 新增列的填充值
    返回:
        扩展后的多级索引DataFrame
    """
    new_cols = []
    for col_tuple in df.columns:
        if col_tuple[target_level] == target_subcol:
            # 为目标子列生成所有新的子子列元组
            for subcol in new_subcols:
                new_tuple = col_tuple[:target_level+1] + (subcol,) + col_tuple[target_level+1:]
                new_cols.append(new_tuple)
        else:
            # 非目标子列补充空层级,保持结构统一
            if len(col_tuple) == target_level+1:
                new_tuple = col_tuple + ('',)
                new_cols.append(new_tuple)
            else:
                new_cols.append(col_tuple)
    # 生成新索引并重新匹配数据
    new_multi_cols = pd.MultiIndex.from_tuples(new_cols)
    return df.reindex(columns=new_multi_cols).fillna(fill_value)

# 使用示例:为Level1的Transport添加National和Import三级子列
new_dfn = add_subcols_to_multilevel(new_df, target_level=1, target_subcol='Transport', new_subcols=['National', 'Import'])

该函数可灵活处理不同层级的扩展需求,适配二级加三级、更高层级扩展等场景。

三、循环方式的正确实现(若需保留循环)

如果一定要用循环,需针对每个一级列单独处理后再拼接:

dfs = []
for level0_col in df.columns.levels[0]:
    # 提取当前一级列下的所有二级列
    sub_df = df[level0_col].copy()
    # 添加Transport二级列
    sub_df['Transport'] = ''
    dfs.append(sub_df)
# 拼接时指定keys作为一级列名,自动生成正确的多级索引
new_df = pd.concat(dfs, axis=1, keys=df.columns.levels[0])

内容的提问来源于stack exchange,提问作者M. Merida-Floriano

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 10:40:58