如何高效将Pandas多校验和列合并为表头-值两列?
高效合并Pandas校验和列的实现方法
问题场景
我从科学仪器获取了一批带校验和的数据文件,已合并为Pandas DataFrame。该DataFrame包含十余列校验和列(列名为校验和表头,如CH_A、CH_B),每行仅对应列有校验和值(其余为NaN)。需要将这些列合并为ChecksumHeaders和ChecksumValues两列:
- 简化示例:初始表含CH_A、CH_B、CH_C列,每行仅对应列有CV_A1/CV_A2/CV_B1/CV_C1等值,其余为NaN;合并后ChecksumHeaders列对应CH_A等表头,ChecksumValues列对应CV等值。
我已通过df.ffill得到ChecksumValues列,但生成ChecksumHeaders列时遇到问题:
- 尝试
np.sum([df[CH].notnull().astype(np.int)*CH for CH in ListOfHeaders]),报错UFuncTypeError: ufunc 'multiply' did not contain a loop with signature matching types (dtype('<U9'), dtype('int32')) -> None - 改用嵌套列表推导式
df['ChecksumHeaders'] = [''.join([ListOfHeaders[idx]*df[CH].notnull().iloc[rowidx].astype(np.int) for idx,CH in enumerate(ListOfHeaders)]) for rowidx in np.arange(len(df))]虽可行,但处理十万行+十余列时效率极低,求更高效的实现方法。
高效解决方案
方法1:用idxmax快速定位非空列
利用每行仅一个非空值的特性,通过布尔矩阵的idxmax直接获取每行非空对应的列名:
# 假设ListOfHeaders是校验和列的列表 checksum_cols = ListOfHeaders df['ChecksumHeaders'] = df[checksum_cols].notnull().idxmax(axis=1)
这是Pandas原生优化的向量操作,十万级数据处理速度极快,完全避免Python级循环。
方法2:用melt重塑表格(同时生成两列)
如果需要同时生成ChecksumHeaders和ChecksumValues,可以直接用melt重塑结构,再过滤NaN值:
checksum_cols = ListOfHeaders # 保留原表其他列的话,指定id_vars参数为非校验和列 melted_df = df.melt( id_vars=[col for col in df.columns if col not in checksum_cols], value_vars=checksum_cols, var_name='ChecksumHeaders', value_name='ChecksumValues' ) # 过滤掉无效的NaN行 melted_df = melted_df.dropna(subset=['ChecksumValues'])
该方法同样是向量级操作,适合需要完整保留原表其他数据的场景,效率远超循环实现。
问题原因说明
- 之前
np.sum方法报错:因为尝试将字符串(列名)与整数相乘,NumPy不支持这种跨类型运算,导致类型不匹配错误。 - 嵌套列表推导式效率低:本质是逐行逐列的Python循环,十万行+十余列会产生百万次循环,远不如Pandas的C级向量操作高效。
内容的提问来源于stack exchange,提问作者Messypuddle
相关产品推荐
相关产品推荐

