Pandas清洗爬取PDF表格数据 合并错误拆分的多行记录
Pandas 异常拆分行合并高鲁棒性实现
问题特征
PDF表格解析时部分单行被错误拆分为3行,行特征固定:
- 拆分首行:
Item列存字符串片段,Quantity、Price为NaN - 拆分中间行:
Item列为NaN,Quantity、Price存有效数值 - 拆分末行:
Item列存剩余字符串片段,Quantity、Price为NaN
其余正常行所有字段均为有效值,需求为将3行拆分块合并为单条规整记录。
原有实现问题
基于索引硬偏移+逐行循环的写法鲁棒性极差:
- 强依赖索引连续递增,只要索引断档、排序变动就会取错值
- 无模式校验,遇到其他类型解析错误会静默输出错误结果
- 逐行赋值性能差,数据量较大时运行效率极低
通用实现代码
核心逻辑为通过行特征打标、连续块分组聚合实现,完全不依赖硬编码行偏移:
import pandas as pd import numpy as np # 标记每行所属类型 df['row_type'] = np.where( df[['Quantity', 'Price']].isna().all(axis=1), np.where(df['Item'].notna(), 'split_part', 'unknown'), np.where(df['Item'].isna(), 'split_mid', 'normal') ) # 生成连续分组ID:每遇到正常行/拆分块首行,分组ID自增,保证单条记录(无论正常还是拆分)同属一组 df['group_id'] = (df['row_type'].isin(['normal', 'split_part'])).cumsum() # 按组聚合合并 merged_df = df.groupby('group_id', as_index=False).agg( # 拼接组内所有非空Item片段 Item=('Item', lambda s: ' '.join(s.dropna().astype(str)).strip()), # 取组内第一个非空的数量、价格值 Quantity=('Quantity', lambda s: s.dropna().iloc[0] if not s.dropna().empty else np.nan), Price=('Price', lambda s: s.dropna().iloc[0] if not s.dropna().empty else np.nan) ) # 异常校验:输出未匹配模式的记录,方便排查脏数据 abnormal_records = merged_df[merged_df[['Item', 'Quantity', 'Price']].isna().any(axis=1)] if not abnormal_records.empty: print(f"检测到{len(abnormal_records)}条不符合拆分模式的异常记录:") print(abnormal_records) # 清理辅助列,输出最终规整结果 final_df = merged_df.drop(columns=['group_id']).dropna(subset=['Item', 'Quantity', 'Price'])
方案优势
- 无索引依赖:不需要假设索引连续,DataFrame经过排序、筛选、重置索引后仍可正常运行
- 自带异常校验:遇到不符合已知模式的脏数据会主动提示,不会静默生成错误结果
- 性能优异:全Pandas原生向量化操作,相比逐行循环在万级以上数据量下性能提升10~100倍
- 易扩展:后续新增其他表字段时,只需在
agg聚合逻辑中补充对应字段的取值规则即可
内容的提问来源于stack exchange,提问作者Tofusoul
相关产品推荐
相关产品推荐

