如何优雅地在Pandas中将带编号重复列折叠为行?
优化Pandas DataFrame重复列折叠实现方案
问题背景
我们需要将包含重复分组列的Pandas DataFrame折叠为标准结构:
- 原DataFrame包含6个公共列,以及3组以
P1/P2/P3标识的重复列组(每组6列) - 目标是将每组重复列与公共列组合后,纵向拼接成统一标准列的DataFrame
- 现有实现依赖固定列顺序,且循环拼接逻辑不够简洁,需优化为不依赖列顺序、更优雅的实现
原列结构
['ID', 'St ti', 'Comp time', 'Email', 'Name', 'Gr Name\n', 'As Na (P1)\n', 'Fr ID (P1)\n', ' Role & royce ', 'Cradle insigt', 'Co-exist network', 'Ample Tree (P1)\n', 'As Na (P2)\n', 'Fr ID (P2)\n', ' Role & royce 2', 'Cradle insigt2', 'Co-exist network2', 'Ample Tree (P2)\n', 'As Na (P3)\n', 'Fr ID (P3)\n', ' Role & royce 3', 'Cradle insigt3', 'Co-exist network3', 'Ample Tree (P3)\n']
目标标准列
['id','st_ti','comp_ti','email','name','gr_na','as_na', 'fr_id','role_royce','cradle_insight', 'coexist_net','ample_tree']
示例输入输出
输入示例(3行24列):
ID St ti Comp time ... Cradle insigt3 Co-exist network3 Ample Tree (P3)\n 0 4 0 3 ... 0 3 0 1 2 3 0 ... 4 0 4 2 1 4 1 ... 4 4 4
输出示例(9行12列):
id st_ti comp_ti ... cradle_insight coexist_net ample_tree 0 4 0 3 ... 0 0 4 1 2 3 0 ... 1 1 0 2 1 4 1 ... 1 3 3 3 4 0 3 ... 1 1 0 4 2 3 0 ... 3 2 4 5 1 4 1 ... 3 4 1 6 4 0 3 ... 0 3 0 7 2 3 0 ... 4 0 4 8 1 4 1 ... 4 4 4
优化实现代码
import pandas as pd import numpy as np np.random.seed(0) # 原列定义 original_cols = ['ID', 'St ti', 'Comp time', 'Email', 'Name', 'Gr Name\n', 'As Na (P1)\n', 'Fr ID (P1)\n', ' Role & royce ', 'Cradle insigt', 'Co-exist network', 'Ample Tree (P1)\n', 'As Na (P2)\n', 'Fr ID (P2)\n', ' Role & royce 2', 'Cradle insigt2', 'Co-exist network2', 'Ample Tree (P2)\n', 'As Na (P3)\n', 'Fr ID (P3)\n', ' Role & royce 3', 'Cradle insigt3', 'Co-exist network3', 'Ample Tree (P3)\n'] # 生成测试DataFrame df = pd.DataFrame(data=np.random.randint(5, size=(3, 24)), columns=original_cols) # ---------------------- 核心优化逻辑 ---------------------- # 1. 定义列映射规则:原列名(或匹配规则)到标准列名的映射 common_col_mapping = { 'ID': 'id', 'St ti': 'st_ti', 'Comp time': 'comp_ti', 'Email': 'email', 'Name': 'name', 'Gr Name\n': 'gr_na' } # 重复组的列匹配规则:原列前缀/特征到标准列名的映射 group_col_mapping = { 'As Na': 'as_na', 'Fr ID': 'fr_id', 'Role & royce': 'role_royce', 'Cradle insigt': 'cradle_insight', 'Co-exist network': 'coexist_net', 'Ample Tree': 'ample_tree' } # 2. 提取公共列并重命名 common_df = df[common_col_mapping.keys()].rename(columns=common_col_mapping) # 3. 识别所有P分组(P1/P2/P3) p_groups = sorted({col.split('(')[-1].strip().strip('\n') for col in df.columns if '(P' in col}) # 4. 处理每个P分组,生成对应的子DataFrame group_dfs = [] for p in p_groups: # 匹配当前P组的所有列 group_cols = [] for key in group_col_mapping: # 找到包含当前key和P标识的列 match_col = next(col for col in df.columns if key in col and p in col) group_cols.append(match_col) # 提取组列并重命名 group_df = df[group_cols].rename(columns={col: group_col_mapping[key] for key, col in zip(group_col_mapping.keys(), group_cols)}) # 和公共列拼接 full_group_df = pd.concat([common_df.reset_index(drop=True), group_df.reset_index(drop=True)], axis=1) group_dfs.append(full_group_df) # 5. 拼接所有分组结果 final_df = pd.concat(group_dfs, ignore_index=True) # 查看结果 print(final_df)
优化点说明
- 不依赖列顺序:通过列名特征匹配(如
(P1)、As Na)定位分组列,即使原列顺序打乱也能正常工作 - 逻辑更简洁:通过映射规则统一管理列名转换,避免硬编码索引范围
- 扩展性更强:若新增P4/P5分组,只需确保列名包含对应标识,无需修改核心逻辑
内容的提问来源于stack exchange,提问作者rpb
相关产品推荐
相关产品推荐

