Pandas拼接分子对描述符DataFrame触发KeyError问题求解
报错根源定位
- 直接触发KeyError的原因是真实运行代码和你贴的最小可复现示例代码不一致:从报错栈打印的出错行可以看到,取第二个分子的描述符时你写的是
cof_df[row['cof2']],漏写了.loc索引器。pandas中直接对DataFrame使用[]操作默认是匹配列名,而非行索引,当分子名diclofenac不存在于描述符表的1600个特征列名中时,就会抛出你看到的KeyError。你单独测试df1.loc[rows['cof1']]能正常运行,是因为这行你正确写了.loc走行索引匹配。 - 潜在的隐性问题:你提到描述符表行数M < 分子对涉及的分子总数,说明部分分子对中的分子没有对应的描述符记录,就算补全
.loc,遇到这类缺失分子名时依然会触发KeyError,需要提前做缺失校验。 - 你当前用的
iterrows逐行循环拼接的写法性能很差,不是pandas推荐的原生实现方案,数据量上来后运行速度会非常慢。
Pandas原生向量化实现方案
用双merge匹配的方案完全替代循环写法,无逐行Python开销,匹配逻辑稳定不会出现索引/列混淆的笔误,代码如下:
import pandas as pd import numpy as np # ---------------------- 基础表示例 ---------------------- # 分子描述符表:不要提前set_index,保留name列用于关联匹配 desc_df = pd.DataFrame([ ['a',1,True,3,4], ['b',55,False,76,87], ['c',9,True,11,12] ], columns=["name", "d1", "d2", "d3", "d4"]) # 分子对表 pair_df = pd.DataFrame({'cof1':['a', 'a','c','b'], 'cof2':['c','b','a','c']}) # -------------------------------------------------------- # 第一次关联:匹配分子对中第一个分子的所有描述符,统一加_cof1后缀 cof1_feat = pair_df.merge( desc_df, left_on='cof1', right_on='name', how='left' # 左连接保留全部分子对,缺失描述符的位置自动填充NaN ).drop(columns='name').add_suffix('_cof1') # 第二次关联:匹配分子对中第二个分子的所有描述符,统一加_cof2后缀 cof2_feat = pair_df.merge( desc_df, left_on='cof2', right_on='name', how='left' ).drop(columns='name').add_suffix('_cof2') # 横向拼接得到最终表,调整列顺序:先放分子名列,再依次放两个分子的1600维特征 final_df = pd.concat([cof1_feat, cof2_feat], axis=1).rename(columns={ 'cof1_cof1': 'cof1', 'cof2_cof2': 'cof2' }) # 筛选列顺序 cof1_cols = [col for col in final_df.columns if col.endswith('_cof1') and col != 'cof2_cof1'] cof2_cols = [col for col in final_df.columns if col.endswith('_cof2') and col != 'cof1_cof2'] final_df = final_df[['cof1', 'cof2'] + cof1_cols + cof2_cols]
这个方案的优势:
- 完全基于pandas原生向量化操作,运行效率比
iterrows循环高1~2个数量级,千级、万级分子对都可以秒级出结果 - 不会出现
.loc漏写导致的列/行索引匹配错误 - 自动兼容分子描述符缺失的场景,不会直接中断运行,后续可以通过
final_df.isna().sum()快速排查哪些分子缺失描述符 - 最终输出列数刚好为2个分子名列 + 1600*2个特征列,完全符合你的需求。
现有循环代码的临时修复方法
如果你暂时不想重构现有逻辑,只需要做两处修改即可解决报错:
- 补全第二个分子取数的
.loc索引器,把出错行的cof_df[row['cof2']]改成cof_df.loc[row['cof2']],和第一个分子的写法保持一致 - 循环前提前校验缺失的分子,避免运行中途中断:
# 提前排查缺失描述符的分子 all_mols = set(pair_df['cof1']).union(set(pair_df['cof2'])) missing_mols = [mol for mol in all_mols if mol not in cof_df.index] if missing_mols: raise ValueError(f"以下分子缺失描述符记录:{missing_mols}")
内容的提问来源于stack exchange,提问作者Charlie Crown
相关产品推荐
相关产品推荐

