
本文介绍如何从含嵌套逻辑的原始数据中提取隐式分组码(如行标题数字),并将其广播至后续明细行,最终生成结构清晰的二维表格,适用于医疗报表、财务明细等具有“汇总-明细”层级关系的数据清洗场景。
在实际数据分析中,我们常遇到一类“伪结构化”数据:原始表格虽为扁平格式,但语义上存在隐式的层级关系——某些行作为分组标题(如纯数字编号),其后若干行属于该组下的明细记录(如带 .xls 后缀的医院标识)。这类数据无法直接使用 pivot_table 处理,因为目标并非数值聚合,而是逻辑分组识别 + 标签广播。
核心思路是:
- 识别分组锚点:利用正则匹配纯数字行(如 "4"、"5"),作为每个明细区块的“Code”;
- 前向填充分组码:对匹配结果执行 ffill(),使每个明细行继承最近上方的分组码;
- 过滤无效行:剔除所有分组锚点行本身(即保留仅含 .xls 的明细行),保留结构化结果。
以下为完整实现代码(基于 pandas):
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:提取纯数字行 → 生成布尔掩码对应的分组码列
nums = df["Row tags"].str.extract(r"^(\d+)$") # 匹配行首到行尾的纯数字
df["Code"] = nums.ffill() # 前向填充,使明细行获得对应分组码
# 步骤2:仅保留明细行(即原"Row tags"列不匹配纯数字的行)
mask = nums.isna().values # True 表示该行不是纯数字(即为明细行)
result = df[mask].reset_index(drop=True)[["Code", "Row tags", "Values"]]
result.columns = ["Code", "Hospital", "Values"] # 重命名列以匹配期望输出
print(result)输出结果:
Code Hospital Values 0 4 100101 - Hospital A.xls 30 1 4 100195 - Hospital B.xls 30 2 4 100105 - Hospital C.xls 40 3 5 100101 - Hospital A.xls 25 4 5 100195 - Hospital B.xls 25
✅ 关键注意事项:
- 正则 r"^(\d+)$" 严格匹配整行纯数字,避免误匹配 100101 这类长数字;若需支持带空格的数字(如 " 4 "),可改用 r"^\s*(\d+)\s*$";
- ffill() 依赖原始行序,务必确保数据顺序不可打乱(如避免未指定 sort=False 的 groupby 或随机采样);
- 若存在开头无分组码的明细行,ffill() 将产生 NaN,建议增加校验:result = result.dropna(subset=["Code"]);
- 本方法时间复杂度为 O(n),远优于循环或 apply,适合万级以内数据;超大规模时可结合 numba 加速正则提取。
该方案跳过冗余的中间布尔列与手动循环,以向量化操作直击本质——将隐式层级显式编码,是处理同类“标题-明细”混合数据的简洁范式。










