模型的上限由数据质量决定。这一步要处理三类问题:盐与混合物、重复记录、以及不适合建模的异常结构。每一类都有明确的判断标准,但过滤强度需要权衡——过松则噪声大,过严则丢失有效数据。
一、结构合理性过滤
from rdkit import Chem
from rdkit.Chem import Descriptors, rdMolDescriptors
ORGANIC = {1, 5, 6, 7, 8, 9, 14, 15, 16, 17, 34, 35, 53} # H,B,C,N,O,F,Si,P,S,Cl,Se,Br,I
def structure_filter(smi):
"""返回 (是否保留, 原因)"""
mol = Chem.MolFromSmiles(smi)
if mol is None:
return False, "unparsable"
n_heavy = mol.GetNumHeavyAtoms()
if n_heavy < 6:
return False, "too_small" # 小于 6 个重原子基本不是类药分子
if n_heavy > 70:
return False, "too_large" # 超出小分子范畴
# 元素检查:排除金属配合物等
elems = {a.GetAtomicNum() for a in mol.GetAtoms()}
if not elems.issubset(ORGANIC):
return False, f"unusual_elements:{elems - ORGANIC}"
# 混合物(清洗后仍多片段说明去盐没处理干净)
if "." in Chem.MolToSmiles(mol):
return False, "mixture"
# 电荷检查
charge = Chem.GetFormalCharge(mol)
if abs(charge) > 2:
return False, f"extreme_charge:{charge}"
# 基本性质范围(宽松,只挡明显异常)
mw = Descriptors.MolWt(mol)
if not (100 <= mw <= 900):
return False, f"mw_out_of_range:{mw:.0f}"
return True, None
二、PAINS 与反应性基团过滤
from rdkit.Chem import FilterCatalog
params = FilterCatalog.FilterCatalogParams()
params.AddCatalog(FilterCatalog.FilterCatalogParams.FilterCatalogs.PAINS_A)
params.AddCatalog(FilterCatalog.FilterCatalogParams.FilterCatalogs.PAINS_B)
params.AddCatalog(FilterCatalog.FilterCatalogParams.FilterCatalogs.PAINS_C)
catalog_pains = FilterCatalog.FilterCatalog(params)
params_b = FilterCatalog.FilterCatalogParams()
params_b.AddCatalog(FilterCatalog.FilterCatalogParams.FilterCatalogs.BRENK)
catalog_brenk = FilterCatalog.FilterCatalog(params_b)
def flag_alerts(smi):
mol = Chem.MolFromSmiles(smi)
if mol is None:
return {"pains": None, "brenk": None}
p = catalog_pains.GetFirstMatch(mol)
b = catalog_brenk.GetFirstMatch(mol)
return {
"pains": p.GetDescription() if p else None,
"brenk": b.GetDescription() if b else None,
}
| 过滤器 | 目标 | 建模时的处理 |
|---|---|---|
| PAINS | 频繁假阳性结构(如儿茶酚、醌类) | 标记但未必删除,见下文 |
| Brenk | 不适合先导化合物的基团(如迈克尔受体、烷化剂) | 虚拟筛选时删,建模时标记 |
| NIH / ZINC | 其他经验规则集 | 按需 |
PAINS 该不该删,取决于用途:
- 虚拟筛选的输出:应该删——避免买到假阳性化合物;
- 训练活性预测模型:建议标记而非删除。PAINS 只是「容易造成干扰」,不代表没有真实活性;删掉可能损失有效数据。更好的做法是加一列标记,建模时作为特征或用于结果解读。
- 训练 HTS 数据模型:应该删——这类数据的假阳性问题最严重(见 245《TDC HTS Group》)。
三、去重(含隐性重复)
from rdkit.Chem import rdMolDescriptors
import pandas as pd
def get_inchikey(smi):
mol = Chem.MolFromSmiles(smi)
return Chem.MolToInchiKey(mol) if mol else None
df["inchikey"] = df["clean_smiles"].map(get_inchikey)
# 完整 InChIKey 去重(区分立体化学)
exact_dups = df["inchikey"].duplicated().sum()
# 骨架层(InChIKey 前 14 位,忽略立体化学与质子化)
df["skeleton"] = df["inchikey"].str[:14]
stereo_dups = df.groupby("skeleton").size()
multi = stereo_dups[stereo_dups > 1]
print(f"完全重复 {exact_dups} 条;"
f"{len(multi)} 个骨架有多个立体异构体")
# 立体异构体是否该合并?取决于任务:
# 活性可能因立体化学差数十倍 → 不应合并
# 但要确认它们不会跨越训练/测试划分(隐性泄漏)
立体异构体跨划分是很隐蔽的泄漏形式:R 构型在训练集、S 构型在测试集,2D 指纹模型看它们几乎一样,测试指标就虚高了。划分时应按 InChIKey 前 14 位(骨架层)分组。
四、异常活性值检测
import numpy as np
# 1) 分布检查
q1, q3 = df["pIC50"].quantile([0.25, 0.75])
iqr = q3 - q1
lo, hi = q1 - 3 * iqr, q3 + 3 * iqr
outliers = df[(df["pIC50"] < lo) | (df["pIC50"] > hi)]
print(f"分布离群点:{len(outliers)} 条(不一定错,需人工看)")
# 2) 活性悬崖检测:结构极相似但活性差很多
# 这些可能是真实的 activity cliff(有价值),
# 也可能是数据错误(需核实)
from rdkit.Chem import rdFingerprintGenerator, DataStructs
gen = rdFingerprintGenerator.GetMorganGenerator(radius=2, fpSize=2048)
fps = [gen.GetFingerprint(Chem.MolFromSmiles(s)) for s in df["clean_smiles"]]
cliffs = []
for i in range(len(fps)):
sims = DataStructs.BulkTanimotoSimilarity(fps[i], fps[i+1:])
for j, s in enumerate(sims, start=i+1):
if s > 0.9 and abs(df["pIC50"].iloc[i] - df["pIC50"].iloc[j]) > 2:
cliffs.append((i, j, s))
print(f"疑似活性悬崖/数据错误:{len(cliffs)} 对,建议抽查")
过滤强度的权衡
| 过滤强度 | 适用 | 风险 |
|---|---|---|
| 宽松(只删明显异常) | 数据量少(< 500) | 噪声大 |
| 中等(+ 元素、性质范围) | 多数情况 | 平衡 |
| 严格(+ PAINS/Brenk 全删) | 数据充足、要求高纯度 | 可能丢失有效数据、缩小适用域 |
关键原则:记录每一步删掉了多少、为什么删。过滤流程必须可审计——半年后要能回答「为什么这个化合物不在数据集里」。
常见坑与提示
- PAINS 在建模时建议标记而非删除,在虚拟筛选输出时才该删;
- 立体异构体跨划分是隐蔽泄漏,划分应按 InChIKey 前 14 位分组;
- 活性悬崖可能是真实 SAR 也可能是数据错误,必须抽查核实;
- 记录每步的删除量与原因,过滤流程必须可审计。
延伸资源
- 上一步:327《清洗 SMILES》、328《RDKit 标准化分子》;下一步:330《计算 ECFP4 Fingerprint》、332《用 Scaffold Split 评估模型真实外推能力》;
- PAINS 概念见「分子表示」模块。