3.2 数据清洗与标准化实战 本节摘要:原始化学数据是脏的:写法非法、盐型混杂、互变异构打架、重复记录各执一词、反应性杂质分子鱼目混珠。本节给出一条六步清洗流水线——解析、去盐、去荷、互变异构归一、去重、警报过滤——配 RDKit 标准化模块的可运行代码,并用一份五千条活性记录的清洗对照案例算清这笔质量账。 上一节的案例里我们只做了三脚架式的清理,真项目远不止于此。本节是第3章的主力节:它把"数据能用"升级为"数据可靠",而可靠性直接决定第6章模型的上限。 从一锅粥到整齐书架:脏数据从哪来 公共数据库的记录来自成千上万个实验室,各自带着各自的书写习惯与登记口径。汇总起来,脏法有六类,堪称"入库六宗罪"。写法非法:价态错误、括号不配对,解析器直接拒绝——这类最显眼,也最易处理。
本节摘要:原始化学数据是脏的:写法非法、盐型混杂、互变异构打架、重复记录各执一词、反应性杂质分子鱼目混珠。本节给出一条六步清洗流水线——解析、去盐、去荷、互变异构归一、去重、警报过滤——配 RDKit 标准化模块的可运行代码,并用一份五千条活性记录的清洗对照案例算清这笔质量账。
上一节的案例里我们只做了三脚架式的清理,真项目远不止于此。本节是第3章的主力节:它把"数据能用"升级为"数据可靠",而可靠性直接决定第6章模型的上限。
公共数据库的记录来自成千上万个实验室,各自带着各自的书写习惯与登记口径。汇总起来,脏法有六类,堪称"入库六宗罪"。写法非法:价态错误、括号不配对,解析器直接拒绝——这类最显眼,也最易处理。盐型混杂:同一化合物以盐酸盐、钠盐、游离碱多种形态出现,拓扑上差一个或几个小分子。溶媒残留:晶体学数据常见水、甲醇等溶剂分子黏在结构上。电荷随意:同一个基团有人写中性、有人写离子。互变异构打架:酮式与烯醇式是同一化学实体的两种图写法,不同来源偏爱不同式。重复记录各执一词:同一分子被测定多次,活性值差异可达一个数量级。
清洗的目标不是把数据洗成"最好看的样子",而是洗成彼此可比的同一口径:同一分子归并成一条,同一基团统一电荷与互变形态,活性值有明确的合并规则。口径是人为选择,但必须一次选定、全程一致。
标准清洗线如下,RDKit 的标准化模块已把中间四步封装好:

from rdkit import Chem from rdkit.Chem.MolStandardize import rdMolStandardize def clean_one(smi, normalizer, tautomer_canonicalizer, uncharger): mol = Chem.MolFromSmiles(smi) if mol is None: return None, "解析失败" # 第一步:拒收 mol = rdMolStandardize.FragmentParent(mol) # 第二步:取母体片段 mol = uncharger.uncharge(mol) # 第三步:电荷中和 mol = tautomer_canonicalizer.Canonicalize(mol) # 第四步:互变归一 mol = normalizer.normalize(mol) # 顺手修正常见书写瑕疵 return Chem.MolToSmiles(mol), "ok" uncharger = rdMolStandardize.Uncharger() normalizer = rdMolStandardize.Normalizer() taut = rdMolStandardize.TautomerEnumerator() test = "CC(=O)Oc1ccccc1C(=O)O.CN" # 阿司匹林混着一点甲胺(示意盐/杂) out, msg = clean_one(test, normalizer, taut, uncharger) print(out, msg) # CC(=O)Oc1ccccc1C(=O)O ok —— 杂质小分子被剥离
六步之后才是去重(按 3.1 节的 InChIKey)与警报过滤。警报过滤针对的是反应性结构——某些基团(如活泼的迈克尔受体、易水解的酯类衍生物)在生化实验中靠假反应频繁"命中"筛选,业内整理了多套警报清单(PAINS、Brenk 等)用于标记。用法上要克制:警报是标记不是死刑,有些真药恰恰带着警报结构,无脑拉黑会错杀整类化学空间。
背景。一次真实感十足的练习:从公共活性库导出某靶点的五千条记录,目标是清洗出一份可建模的数据集,并搞清楚每一步各扔掉、改写了多少。清洗不看总量看流量表——每一步的计数就是数据质量报告。
操作与结果。按流水线跑完后,逐环节统计大致是这样的分布:解析环节拒收约百条(约百分之二,多为价态错误与不完整的环号);去盐与溶媒剥离改写约七百条(公共库里盐型记录占大头是常态);电荷与互变归一各改写数百条;InChIKey 去重把记录数压掉约两成——五千条记录往往只有四千个左右独特分子,热门靶点的重复测定率就是这么高;警报过滤标记出约百条含反应性基团,其中半数经人工复核后保留(结构确有活性依据),半数剔除。
解读。这组数字有两个教学点。其一,清洗不是小修小补而是大比例手术:近四成记录被改写或合并,不做清洗直接建模,等于把同一分子的多种形态当成多种分子喂给模型,重复结构携带的活性噪声会直接污染训练。其二,每一步的计数都是可审计的证据:清洗报告里"去重合并率百分之二十"这种数字,在项目复盘和监管提交时的价值远超一句"我们清洗过了"。
变式。两个方向的进阶。数据更脏时(仪器原始输出、手录数据),流水线前面要加"格式归一"步骤:单位统一、缺失值规则、非结构字段(如"活性强"这种定性描述)的编码策略。数据更贵时(自有实验数据),流程要反过来先立规范再产数据——这正是下一节 FAIR 治理的主题:清洗发生在登记之前,成本才最低。
既然清洗报告是质量证明,它的栏目就该像财务报表一样固定。一份经得起审计的报告至少五栏:输入概况(来源、条数、抽取日期与版本号);逐环节流量表(每步改写多少、淘汰多少,与图 3-2 的六步一一对应);改写抽样(每类改写随机抽十条前后对照,人工可快速复核规则是否如预期工作);残留已知问题(比如"某来源的记录缺立体信息,已标注未解析出"——清洗不消灭问题,只显式移交问题);可复现参数(每个环节用的规则版本与参数,配上代码提交号)。固定栏目的好处是报告可以横向比较:本月的清洗流量表与上月一对照,输入数据质量的漂移自己会说话——某来源的解析失败率突然翻倍,八成是上游改了导出格式。