
本文介绍一种高效方法,利用正则提取与前向填充技术,将含隐式分组标识(纯数字行)和子项(含 `.xls` 的行)的混合列,重构为标准二维结构化表格,无需 pivot 操作。
在实际数据处理中,常遇到“头部标签 + 子项列表”的嵌套式扁平结构(如导出报表、日志摘要等),其中某列(如 Row tags)交替出现纯数字(代表分组 ID)和带后缀的文本(代表该组下的明细项)。目标并非传统透视(pivot),而是逻辑分组重建:将每个数字作为 Code,向下广播至其后所有非数字行,最终过滤掉数字行本身,形成规整的二维关系表。
核心思路分三步:
- 识别分组锚点:用正则 ^(\d+)$ 精确匹配整列为纯数字的行(排除 100101 这类混杂数字);
- 传播分组码:对匹配结果使用 ffill()(前向填充),使每个数字自动“覆盖”其后的所有子项行;
- 过滤主体数据:仅保留原 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 分批处理,保持内存友好性。










