第2章:分子描述符基础归纳总结
说实话,我刚入行做QSAR那会儿,最头疼的就是分子描述符。别人跑一个模型,R²能有0.9,我跑出来就0.3。后来才发现,问题出在描述符上——要么选错了,要么没处理好。这一章,我就把这些年积累的分子描述符经验,掰开了揉碎了给你讲讲。
2.1 什么是分子描述符
分子描述符,说白了就是分子的「数字身份证」。它是用数学或计算化学的方法,把分子的结构信息转成一串数字。有了这串数字,计算机才能理解分子,模型才能学出规律。
我习惯把描述符分成这几类:
- 0D描述符:比如分子量、原子个数。信息量最少,但最稳定。
- 1D描述符:比如分子式、官能团计数。比0D多点儿信息。
- 2D描述符:基于分子图论的拓扑指数。比如Wiener指数、Zagreb指数。这类描述符很常用,我项目中80%的模型都靠它。
- 3D描述符:需要三维构象。像CoMFA、CoMSIA里的立体场和静电场。计算量大,但信息丰富。
- 4D描述符:考虑构象集合和时间演化。说实话,我一般不用,除非数据量特别大。
我的经验:别一上来就追求复杂描述符。先跑2D描述符,模型不行再往上加。过度设计是新手最常见的毛病。
2.2 描述符的计算与工具
现在工具很多,我主要用这几套:
| 工具 | 描述符数量 | 适用场景 | 我的评分 |
|---|---|---|---|
| RDKit | 200+ | 日常筛选、预实验 | ⭐⭐⭐⭐⭐ |
| PaDEL-Descriptor | 1400+ | 全面的特征工程 | ⭐⭐⭐⭐ |
| Mordred | 1800+ | 学术研究 | ⭐⭐⭐⭐ |
| Dragon | 5000+ | 工业级应用 | ⭐⭐⭐(需付费) |
举个例子,用RDKit算描述符很简单:
from rdkit import Chem
from rdkit.Chem import Descriptors
mol = Chem.MolFromSmiles('CCO') # 乙醇
mw = Descriptors.MolWt(mol)
logp = Descriptors.MolLogP(mol)
hbd = Descriptors.NumHDonors(mol)
print(f"分子量: {mw:.2f}")
print(f"LogP: {logp:.2f}")
print(f"氢键供体数: {hbd}")
输出结果:
分子量: 46.07
LogP: -0.14
氢键供体数: 1
2.3 描述符的筛选策略
算完描述符,你会发现一个问题——太多了。有人算出来几千个描述符,直接扔进模型跑。你想想看,这有多容易过拟合?
我一般按这几步来筛:
- 常数筛:方差接近0的描述符,直接扔掉。
- 相关性筛:两个描述符相关系数 > 0.95,保留一个。
- 重要性排序:用随机森林或LASSO,找top N个。
技巧:我通常保留50-200个描述符。太少欠拟合,太多过拟合。你可以从100个开始调。
做常数筛选时,我习惯这样写:
import pandas as pd
import numpy as np
# 假设 df 是描述符矩阵
def remove_constant_features(df, threshold=0.01):
variances = df.var()
to_remove = variances[variances < threshold].index.tolist()
print(f"移除 {len(to_remove)} 个常数/近常数特征")
return df.drop(columns=to_remove)
避坑:我曾经踩过一个坑——直接用默认阈值筛选分子量。结果某个系列分子量差别很小,但活性差别很大。后来我改为按数据集动态调整阈值,模型才正常。
2.4 描述符的标准化与缩放
描述符尺度差异很大。分子量几百,logP可能只有几。你不做缩放,模型就会偏向量级大的特征。
我推荐两种方式:
- Z-score标准化:均值为0,标准差为1。适合有异常值的数据。
- Min-Max缩放:映射到[0,1]。适合范围固定的描述符(比如是否为芳香环)。
代码实现:
from sklearn.preprocessing import StandardScaler, MinMaxScaler
# Z-score
scaler_z = StandardScaler()
df_z = pd.DataFrame(scaler_z.fit_transform(df), columns=df.columns)
# Min-Max
scaler_mm = MinMaxScaler()
df_mm = pd.DataFrame(scaler_mm.fit_transform(df), columns=df.columns)
关键点:记住,只用训练集的数据去拟合scaler,然后transform训练集和测试集。别把测试集数据混进去,这是泄露。
2.5 常用描述符一览
下面这张表,我做了很多项目才总结出来的:
| 类别 | 典型描述符 | 含义 | 适用性 |
|---|---|---|---|
| 物理化学 | MolLogP, MolWt, TPSA | 脂溶性、分子量、极性表面积 | ADME/Tox预测 |
| 拓扑 | Wiener, Zagreb, BalabanJ | 分子连通性、分支度 | 结构-活性关系 |
| 电性 | PartialCharge, DipoleMoment | 电荷分布、偶极矩 | 作用机制研究 |
| 立体 | PMI1, PMI2, PMI3 | 分子形状的主惯性矩 | 3D构象分析 |
| 指纹 | MorganFP, MACCS, AtomPair | 子结构存在性 | 相似性搜索、分类 |
2.6 本章知识体系
下面这张图,是我做了十多年QSAR总结出来的框架。先看定义,再算工具,然后筛选和缩放,最后应用到模型里。每一步都环环相扣:
2.7 常见问题与避坑指南
这些年下来,我发现很多问题都是共通的。列出来,你碰到类似情况可以直接查:
- 描述符太多,模型跑不动:先用随机森林的特征重要性排序,砍到100个以内。
- 模型不收敛:检查一下描述符有没有做标准化。我有个项目就是这样,标准化后收敛速度快了5倍。
- 训练集和测试集表现差异巨大:大概率是特征泄露了。检查你有没有用全数据做特征筛选。
- R²很高但预测不准:描述符过多导致过拟合。减少描述符数量,或者加正则化。
重要:我曾经被审稿人指出,训练集和测试集描述符分布不一致。后来我学会了一个检查方法:每次做完描述符,就画个t-SNE图看看分布。分布重叠不好,换个描述符组合。
好了,分子描述符的基础就这些。记住,描述符是QSAR的基石——地基打不好,上面盖多漂亮的模型都白搭。我建议你动手算一组数据,亲自走一遍筛选和缩放的流程。光看不练,三天就忘光了。