如何将包含层级索引的列转换为结构化宽表(按数字分组并关联后续行)

1次阅读

如何将包含层级索引的列转换为结构化宽表(按数字分组并关联后续行)

本文介绍一种高效方法,利用正则提取与前向填充技术,将含隐式分组标识(纯数字行)和子项(含 `.xls` 的行)的混合列,重构为标准二维结构化表格,无需 pivot 操作。

在实际数据处理中,常遇到“头部标签 + 子项列表”的嵌套式扁平结构(如导出报表、日志摘要等),其中某列(如 Row tags)交替出现纯数字(代表分组 ID)和带后缀的文本(代表该组下的明细项)。目标并非传统透视(pivot),而是逻辑分组重建:将每个数字作为 Code,向下广播至其后所有非数字行,最终过滤掉数字行本身,形成规整的二维关系表。

核心思路分三步:

  1. 识别分组锚点:用正则 ^(d+)$ 精确匹配整列为纯数字的行(排除 100101 这类混杂数字);
  2. 传播分组码:对匹配结果使用 ffill()(前向填充),使每个数字自动“覆盖”其后的所有子项行;
  3. 过滤主体数据:仅保留原 Row tags 不匹配数字的行(即 .xls 行),此时 Code 列已正确关联。

以下是完整可执行代码示例:

import pandas as pd  # 构建原始数据 df = pd.DataFrame({     "Row tags": [         "4",         "100101 - Hospital A.xls",         "100195 - Hospital B.xls",         "100105 - Hospital C.xls",         "5",         "100101 - Hospital A.xls",         "100195 - Hospital B.xls"     ],     "Values": [100, 30, 30, 40, 50, 25, 25] })  # 步骤 1:提取纯数字行(返回 DataFrame,单列) nums = df["Row tags"].str.extract(r"^(d+)$")  # 步骤 2:前向填充 Code,并赋值为新列 df["Code"] = nums[0].ffill()  # 注意:extract 返回 DataFrame,取第 0 列  # 步骤 3:仅保留非数字行(即子项行),同时保留 Code 和原始列 result = df[nums[0].isna()].reset_index(drop=True)[["Row tags", "Values", "Code"]] result.columns = ["Hospital", "Values", "Code"]  # 重命名列以匹配期望输出  print(result)

输出结果:

Hospital  Values Code 0  100101 - Hospital A.xls      30    4 1  100195 - Hospital B.xls      30    4 2  100105 - Hospital C.xls      40    4 3  100101 - Hospital A.xls      25    5 4  100195 - Hospital B.xls      25    5

关键注意事项

  • 正则 ^(d+)$ 中的 ^ 和 $ 至关重要,确保只匹配整列纯数字(如 “4”),避免误匹配 “100101”;
  • ffill() 依赖行序,原始数据顺序不可打乱,否则分组关系将错位;
  • 若存在连续多个数字行(如 4, 6, 7),每个数字仅影响其后直到下一个数字前的子项——这正是业务逻辑所要求的“块级分组”;
  • 最终列名可通过 rename() 或直接索引赋值灵活调整,满足下游分析或导出需求。

该方法简洁、高效、无循环,完全基于 pandas 向量化操作,适用于万级以内数据;对于超大数据集,亦可结合 chunksize 分批处理,保持内存友好性。

text=ZqhQzanResources