第3章:分布(Distribution)模型评估方法

评估的整体逻辑

分布模型预测的是药物从血液往组织里跑的程度,说白了就是看药物在体内的“地盘”有多大。我个人习惯把分布模型分成两类:一类预测稳态分布容积(Vss),另一类预测组织-血浆分配系数(Kp)。前者告诉你整体扩散范围,后者帮你细化到每个器官。

评估分布模型,我通常看这三块:

  • 外部验证:拿没见过的化合物来测,这是硬标准。
  • 内部验证:用训练集本身评估模型稳定性。
  • 适用范围:搞清楚你的模型对哪些化合物靠谱。

下面这张图是我做项目时总结的评估框架,你想想看,是不是每步都对应一个实际问题?

分布模型评估方法框架 已训练的分布模型 ① 外部验证 用全新化合物测试 保留测试集 ② 内部验证 交叉验证 / 自举 Y随机化测试 ③ 适用范围 AD距离 / 杠杆值 Williams图 回归指标 RMSE / MAE / R² / Q²F 几何平均折留误差 稳定性指标 Q²-LOO / Q²-Boot Y随机化 R²Y/Q²Y 应用界限 阈值线 / 离群标识 训练集覆盖边界 综合判断:模型是否可靠 ? 外部 + 内部 + 范围 三条件

外部验证指标

外部验证是我最看重的部分。做模型不是为了在论文里装样子,而是要拿来预测新化合物的。

实际应用中,常见的回归指标有这些:

指标公式 / 说明我关心的阈值
RMSE \(\sqrt{\frac{\sum_{i=1}^{n}(\hat{y}_i - y_i)^2}{n}}\) <0.5 log 单位(Vss常用)
MAE \(\frac{\sum_{i=1}^{n}|\hat{y}_i - y_i|}{n}\) <0.3 log 单位
R² 决定系数 >0.6(分布模型很难>0.8)
Q²_F 外部预测决定系数 >0.5 说明有预测能力
Geometric Mean Fold Error 预测/实测比值的几何均值 1.5-2.0以内可以接受

举个例子:我做过一个Vss预测模型,测试集有45个化合物。RMSE在0.42 log单位,R²是0.58。当时有同事嫌R²低,但你看分布模型的实验测定误差本身就很大(同一化合物不同实验室能差2倍),所以0.58实际是个不错的数。后来这个模型帮我们筛选了300多个先导化合物中哪些容易在组织中滞留。

我的使用习惯:我不会单独看RMSE或R²,而是把散点图一块儿看。有时候R²挺高,但斜率和截距跑偏了,那模型也是有问题的。我一般会跑一次这个检查:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import mean_squared_error, r2_score

y_true = [1.2, 2.5, 3.1, ...]  # 实际logVss
y_pred = [1.0, 2.7, 2.9, ...]  # 预测logVss

rmse = np.sqrt(mean_squared_error(y_true, y_pred))
r2 = r2_score(y_true, y_pred)
mae = np.mean(np.abs(np.array(y_true) - np.array(y_pred)))

print(f"RMSE: {rmse:.2f}")
print(f"R²: {r2:.2f}")
print(f"MAE: {mae:.2f}")

# 再计算几何平均折留误差
fold_error = np.mean(np.abs(10 ** (y_true - y_pred) - 1))
print(f"Geometric Mean Fold Error: {fold_error:.2f}")

内部验证指标

内部验证说白了就是“自己考自己”,看看模型在训练集上是不是过拟合了。很多新手模型外部验证一塌糊涂,内部验证却漂亮得很,这就是问题。

留一法交叉验证(Q²-LOO)

这个做法我挺喜欢的,虽然计算量大。每次拿一个样本出来当测试,其余训练,最后算预测值和真实值的Q²。我在项目中遇到过好几次:模型在训练集上R²>0.9,但Q²-LOO只有0.3。这就说明模型在背答案,不是真学到了东西。

避坑指南:我曾经犯过一个错。用留一法评估一个分布模型,Q²看起来不错(0.72),可一遇到外部数据就掉到0.2。后来发现——训练集里有很多相似结构的化合物,留一法测不出“族外”预测能力。所以现在我一定会做“族留出交叉验证”:把同一骨架的化合物整个移除,这才算数。

Y随机化测试

这个测试特简单:把训练集里的实测值打乱,然后用原来的特征重新建模。如果打乱后还能得到高R²或高Q²,那你的模型基本就是瞎猫碰死老鼠了。

我在报告里一般这样展示:

Randomization results:
Original model: R² = 0.74,  Q²_LOO = 0.53
- Random run 1:  R² = 0.12,  Q²_LOO = -0.18
- Random run 2:  R² = 0.08,  Q²_LOO = -0.21
- Random run 3:  R² = 0.15,  Q²_LOO = -0.14
- Random run 4:  R² = 0.05,  Q²_LOO = -0.30
- Random run 5:  R² = 0.10,  Q²_LOO = -0.19
cR²Y = 0.85 (cut-off > 0.5 通过)

你看,打乱之后R²和Q²全掉到0附近甚至负值,说明模型没有误用随机相关性。

适用范围(Applicability Domain)

这个我觉得是分布模型里最容易忽略的一块。模型不是万能的,它只在训练集覆盖的化学空间里才有效。你拿一个与训练集结构完全不同的新化合物去预测,结果基本就是掷骰子。

适用范围的核心方法是Williams图

  • 横轴:杠杆值(h)——表示化合物在化学空间里的“奇怪程度”。
  • 纵轴:标准化残差——预测偏差有多大。
  • 阈值线:h* = 3(k+1)/n,其中k是变量个数,n是训练集样本数。

实际解读规则:

  • 落在 h < h* 且 |残差| < 3 的化合物 → 安全区域,预测可信。
  • 落在 h > h* 且残差小的化合物 → 结构离群但预测还好,要谨慎。
  • 落在 h > h* 且残差大的化合物 → **不可信,不能用**。

生成Williams图的代码可以这样写:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.covariance import MinCovDet

# 假设X_train是训练集的分子描述符矩阵
mcd = MinCovDet().fit(X_train)
# 计算马氏距离,再转成杠杆值
mahalanobis = mcd.mahalanobis(X_train)
n_train, k = X_train.shape
h = mahalanobis / (n_train - 1)
h_star = 3 * (k + 1) / n_train  # 阈值

# 假设标准化残差已经计算好存在std_residuals中
plt.figure(figsize=(6,5))
plt.scatter(h, std_residuals, c='#3498db', edgecolors='#2980b9')
plt.axhline(y=3, color='#e74c3c', linestyle='--', label='±3 σ')
plt.axhline(y=-3, color='#e74c3c', linestyle='--')
plt.axvline(x=h_star, color='#f39c12', linestyle='--', label=f'h* = {h_star:.3f}')
plt.xlabel('Leverage (h)')
plt.ylabel('Standardized Residuals')
plt.title('Williams Plot - Vss Model AD')
plt.legend()
plt.tight_layout()
plt.show()

分布模型评估的可接受标准

你想想看,不同场景下对模型的要求是不一样的。我给一个参考基准表:

用途RMSE (log单位)R²适用范围覆盖率
早期先导筛选(高通量)< 0.7> 0.4> 70% 待测化合物落在AD内
先导优化(中等通量)< 0.5> 0.5> 80%
候选化合物申报支撑< 0.3> 0.7> 90% + 全部进行外部实验验证

⚠ 注意:R²在分布模型里很少超过0.8。如果你看到一个分布模型的R² > 0.9,赶紧检查:

  • 是不是训练集有重复或高度相似化合物?
  • 是不是用了太多描述符(过拟合)?
  • 是不是测试集太小或者分布太窄?

我曾经见过一个团队号称Vss预测R²达到0.95,后来发现是只用了15个化合物做测试,而且都是脂肪胺类。这种模型放到真实项目里根本没法用。

总结一下我的评估策略

嗯,写到这里,我习惯的做法是这样的:

  1. 先跑外部验证,看RMSE和Q²_F是否达标,同时画散点图检查系统误差。
  2. 再做内部验证,用留一法或5折交叉验证,看与外部指标是否一致。
  3. Y随机化必须有,如果打乱后R²还>0.2,这个模型基本可以扔了。
  4. 画Williams图,明确哪些新化合物可以放心用,哪些不行。
  5. 最终决策:外部+R²和Q²不低于0.5,AD覆盖率不低于70%,才敢拿出去给项目组用。

一点个人经验:我最开始做分布模型时总觉得外部验证和内部验证分开处理就行。后来发现最大的坑不是模型的精度不够,而是适用范围没画清楚。项目组拿着模型乱预测,出了问题全怪模型。所以我现在写任何分布模型评估报告,第一页就贴Williams图,告诉所有人:红线外面的化合物,我不会给预测值。