Bohrium
robot
新建

空间站广场

论文
Notebooks
比赛
课程
Apps
我的主页
我的Notebooks
我的论文库
我的足迹

我的工作空间

任务
节点
文件
数据集
镜像
项目
数据库
公开
深度学习模型在反向找靶中优于传统方法吗[1]
AI4S
AI4S
yufeng
发布于 2023-09-26
推荐镜像 :Basic Image:ubuntu20.04-py3.10
推荐机型 :c8_m16_cpu
赞 2
1
1
chembl33(v1)

深度学习模型在反向找靶中优于传统方法吗[1]

©️ Copyright 2023 @ Authors
作者: 余峰 📨
日期:2023-09-25
共享协议:本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
快速开始:点击上方的 开始连接 按钮,选择 registry.dp.tech/dptech/ubuntu:20.04-py3.10镜像CPU:c8_m16_cpu 或更高配置机型即可开始。

代码
文本

反向找靶

反向找靶,是给定小分子化合物和候选蛋白库,预测出给定小分子的所有可能的靶蛋白。

反向找靶在药物发现的很多环节都有着重要作用:

  1. 表型药物机制阐明;
  2. 脱靶效应分析与增效减毒;
  3. 老药新用;

反向找靶任务和核心是预测蛋白-小分子的亲和力,采用的方法大概有三类:

  1. 基于docking的方法,如vina,glide等;
  2. 基于蛋白序列的方法,如conplex,transformCPI等;
  3. 基于ligand/descriptor特征的方法,如swisstarget等。

后两种方法往往可以使用很多数据和特征,借助预训练大模型等深度学习建模方法,取得了雨后春笋般的发展,但是其预测结果,并不能很好地对应上实验结果。

Benchmark

再加上很多方法的Benchmark Setting各不相同,相互之间很难比较。我们有必要做一个公平合理的Benchmark,来挑选出最好用的方向找靶工具。

制作Benchmark的核心是指标,数据和基准方法。这里面每一点都需要精心设计,作为本系列Notebook的第一篇,我们先详细介绍一下如何整理数据。

数据集

亲和力有关的数据集有很多,如Binding affinity、BindingDB、PDBBind等等,为了收集尽可能大且靠谱的数据,我们选择了ChEMBL作为我们的数据源。

ChEMBL数据有超过一百万个蛋白-小分子的亲和力数据,后续内容将围绕ChEMBL数据的获取和清洗展开。

数据获取

ChEMBL提供了很多获取方式,比如提供python api逐条获取数据,但是考虑到速度、稳定性、筛选条件的全面性之后,我们直接下载和处理ChEMBLdb数据库。

ChEMBLdb数据库最新版本可以从此下载URL,我们现在其中的数据库文件,如chembl_33_sqlite.tar.gz。

下载之后,我们可以在用本地软件加载这个数据库,如DB Browser for SQLite (macos),然后我们可以用SQL对数据进行初步清洗,参考的SQL如下:

代码
文本
[ ]
SELECT
m.chembl_id AS compound_chembl_id
,s.canonical_smiles
,act.standard_type
,act.standard_relation
,act.standard_value
,act.standard_units
,t.chembl_id AS target_chembl_id
,t.pref_name AS target_name
,t.organism
,cs.accession AS UniProt_Accessions
FROM compound_structures s
JOIN molecule_dictionary m ON s.molregno = m.molregno
JOIN activities act ON m.molregno = act.molregno
JOIN assays a ON act.assay_id = a.assay_id
JOIN target_dictionary t ON a.tid = t.tid
JOIN target_components tc ON t.tid = tc.tid
JOIN component_class cc ON tc.component_id = cc.component_id
JOIN component_sequences cs ON cc.component_id = cs.component_id
JOIN protein_classification pc ON cc.protein_class_id = pc.protein_class_id
WHERE m.molecule_type = 'Small molecule'
AND t.target_type = 'SINGLE PROTEIN'
AND a.assay_type = 'B'
AND act.standard_relation IN ('=', '<', '~', '<=', '<<')
AND act.standard_type IN ('IC50', 'EC50', 'Ki', 'Kd')
AND act.standard_units IN ('nM', 'ug.mL-1')
AND act.standard_value != 'NULL'
AND act.standard_value <> ''
AND act.standard_value IS NOT NULL
AND t.organism != 'NULL'
AND t.organism <> ''
AND t.organism IS NOT NULL
代码
文本

这里可以根据我们的需求对WHERE中的筛选条件进行选择,大部分条件都可以根据字面意思来理解,其中assay_type = 'B'表示bingding亲和力相关的实验数据。

数据清洗 接下来会进一步做细致的清洗工作:

  1. 只取standard_units==nM的数据,其他数据不可标准使用,较少可弃
  2. standard_value(浓度)去掉异常值:负数,超大数
  3. canonical_smiles用rdkit重新转一次,不同软件/版本的可能不同
  4. 一个canonical_smiles可能对应多个compound_chembl_id,
  5. 同一版本Chembl数据中,一个compound_chembl_id只对应一个canonical_smiles
  6. Chembl不同版本会修改compound_chembl_id对应的互变异构体,用最新版
  7. 计算分子间fingerprint相似性,top K中大部分可能都跟某一个分子相关,需去掉bias
  8. 去掉train data中异常大的分子可以增加模型batchsize,如重原子超过100的小分子,数目少,可去掉

具体的python脚本如下:

代码
文本
[ ]
v1, v2, v3 = 31, 32, 33
f3 = f'/bohr/chembl33-cd0h/v1/chembl{v3}.csv'
df3 = pd.read_csv(f3, header=0)
df3 = df3[df3['standard_units']=='nM'][df3['standard_value']>0] # 1184642
print(f'raw chembl{v3}: {df3.shape}')

old_smiles = set(df3['canonical_smiles'].unique())
old_smiles = list(old_smiles) # 554587
def CanonSmiles(smiles):
return Chem.CanonSmiles(smiles)
with Pool(cpu_count()) as p:
new_smiles = list(tqdm(p.imap(CanonSmiles, old_smiles), total=len(old_smiles)))
old_new = dict(zip(old_smiles, new_smiles))
df3['canonical_smiles'] = df3['canonical_smiles'].map(old_new).fillna(df3['canonical_smiles'])

df3 = df3.groupby(["canonical_smiles", "UniProt_Accessions", "organism"])[["standard_value"]].median().reset_index() # 903222
# df3.groupby(["canonical_smiles", "UniProt_Accessions"])[["standard_value"]].max().reset_index() # 903217
# df3 = df3.loc[df3.groupby(["canonical_smiles", "UniProt_Accessions"])["standard_value"].idxmax()] # 903217
print(f'deduplicate chembl{v3}: {df3.shape}')

def heavy_atom_num(smiles):
mol = Chem.MolFromSmiles(smiles)
return mol.GetNumHeavyAtoms()
smiles3 = list(set(df3['canonical_smiles'].unique()))
with Pool(cpu_count()) as p:
heavy_atom_num = list(tqdm(p.imap(heavy_atom_num, smiles3), total=len(smiles3)))
smiles_atoms = dict(zip(smiles3, heavy_atom_num))
df3['heavy_atom_num'] = df3['canonical_smiles'].map(smiles_atoms)

# df3.standard_value.hist(bins=200, range=(0, 2000), alpha=0.5)
df3.heavy_atom_num.hist(bins=200, range=(0, 200), alpha=0.5)
dpath = '/mnt/vepfs/users/yufeng/data/chembl'
df3.to_csv(f'{dpath}/chembl33_refine.csv', index=False)
代码
文本

数据切分

整理好了数据之后,需要把数据分成训练集和测试集,为了防止数据泄露,需要根据数据的相似性做聚类,然后把不同的聚类分到训练集和测试集中,来测试模型的泛化效果。

由于我们的任务是反向找靶,模型需要的是对于小分子的泛化能力(因为蛋白候选库都是一样的),可以按照小分子拆分数据到训练集和测试集。

聚类

由于小分子的特征分布有着极多的离群点,一般的聚类算法,如kmeans等很难得到稳定聚类结果,经常需要使用基于密度的聚类算法,如taylor butina聚类算法。

基于密度的聚类算法,需要首先计算出数据点之间的两两相似性。

数据相似性

为了计算小分子之间的相似性,需要先计算小分子的fingerprint,这里可以选用morgan fingerprint。

我们清洗的ChEMBL数据中,小分子数超过40万,计算小分子的两两相似性需要计算800亿个pair,复杂度特别高,对于代码的内存管理和速度优化都有着极高的要求。

经过测试,当小分子数少于10万时,仍然可以使用rdkit来获得可以容忍的内存和速度要求:

代码
文本
[ ]
dpath = '/mnt/vepfs/users/yufeng/data/chembl'
df3 = pd.read_csv(f'{dpath}/chembl33_refine.csv', header=0)
all_smiles = list(df3[df3['standard_value']<=1000][df3.heavy_atom_num<=100]['canonical_smiles'].unique()) # 412344
def smiles2fp(smiles):
mol = Chem.MolFromSmiles(smiles)
fp = FingerprintMols.FingerprintMol(
mol, minPath=1, maxPath=7,
fpSize=1024, bitsPerHash=2,
useHs=True, tgtDensity=0, minSize=128
)
return fp

def fp_batch(smiles_list):
with Pool(cpu_count()) as p:
return p.map(smiles2fp, tqdm(smiles_list, total=len(smiles_list)))

fp_all = fp_batch(all_smiles)
代码
文本

但是我们现在的小分子数超过40万,rdkit处理的内存和速度要求都已经不可被接受。

为此我们介绍一款商用软件chemfp,其聚类功能免费,刚好可以满足我们的需求:

代码
文本
[ ]
# len(all_smiles) # 412344
tmp_smiles = all_smiles#[:5]
pd.DataFrame({'smi': tmp_smiles, 'idx': range(len(tmp_smiles))}).to_csv(f'{dpath}/smi_idx.smi', sep='\t', index=False, header=False)
# use rdkit2fps from chemfp package
!rdkit2fps /mnt/vepfs/users/yufeng/data/chembl/smi_idx.smi --morgan > /mnt/vepfs/users/yufeng/data/chembl/smi_idx.fps
!python /mnt/vepfs/users/yufeng/code/chembl/taylor_butina.py --profile --threshold 0.6 /mnt/vepfs/users/yufeng/data/chembl/smi_idx.fps -o /mnt/vepfs/users/yufeng/data/chembl/smi_idx.clusters
# reference
# https://zhuanlan.zhihu.com/p/512213652
# https://zhuanlan.zhihu.com/p/519371957
# https://chemfp.com/license/
代码
文本

聚类之后,我们可以获得接近2万个outlier分子作为测试集test_smiles,这些数据点都是单点聚类,即每个类中只有单个分子或其互变异构体。

剩下的其他数据可以作为训练集。

为了方便后续计算指标,我们把不同种属的数据分开评测,即人、大鼠、小鼠:

代码
文本
[ ]
human_smiles = df_test[df_test.organism=='Homo sapiens'].canonical_smiles.unique()
rat_smiles = df_test[df_test.organism=='Rattus norvegicus'].canonical_smiles.unique()
mus_smiles = df_test[df_test.organism=='Mus musculus'].canonical_smiles.unique()

pd.DataFrame(human_smiles).to_csv('/mnt/vepfs/users/yufeng/data/chembl/human_smi.txt', index=False, header=False, sep='\n')
pd.DataFrame(rat_smiles).to_csv('/mnt/vepfs/users/yufeng/data/chembl/rat_smi.txt', index=False, header=False, sep='\n')
pd.DataFrame(mus_smiles).to_csv('/mnt/vepfs/users/yufeng/data/chembl/mus_smi.txt', index=False, header=False, sep='\n')
代码
文本
[ ]
# protein candidate
human_seq = df3[df3.organism=='Homo sapiens'].UniProt_Accessions.unique() # 2637
rat_seq = df3[df3.organism=='Rattus norvegicus'].UniProt_Accessions.unique() # 641
mus_seq = df3[df3.organism=='Mus musculus'].UniProt_Accessions.unique() # 616
cbl_seq = cbl_seq.rename(columns={'UniProt_Accessions': 'Entry', 'sequence': 'Sequence'})
cbl_seq[cbl_seq['Entry'].isin(human_seq)].to_csv(f'{dpath}/chembl33_human_seq.tsv', sep='\t', index=False)
cbl_seq[cbl_seq['Entry'].isin(rat_seq)].to_csv(f'{dpath}/chembl33_rat_seq.tsv', sep='\t', index=False)
cbl_seq[cbl_seq['Entry'].isin(mus_seq)].to_csv(f'{dpath}/chembl33_mus_seq.tsv', sep='\t', index=False)
# cbl_seq['UniProt_Accessions'] = '>' + cbl_seq['UniProt_Accessions'].astype(str)
# chembl33_fasta = cbl_seq[['UniProt_Accessions', 'sequence']]
# chembl33_fasta.to_csv(f'{dpath}/chembl33.fasta', index=False, header=False, sep='\n')
代码
文本

参考文献

如果您想进一步了解,您可以阅读下述文章:

  1. https://zhuanlan.zhihu.com/p/512213652
  2. https://zhuanlan.zhihu.com/p/519371957
  3. https://chemfp.com/license/
代码
文本
AI4S
AI4S
已赞2
本文被以下合集收录
机器学习在化学中的应用
唐浩程
更新于 2023-10-15
5 篇0 人关注
推荐阅读
公开
Uni-Core Tutorial 101
Deep LearningTutorial
Deep LearningTutorial
jixh@dp.tech
发布于 2023-11-08
1 赞2 评论
公开
TBPLaS入门教程
紧束缚模型对角化方法时间演化方法大尺度模拟中文
紧束缚模型对角化方法时间演化方法大尺度模拟中文
李云海
发布于 2023-07-26
9 赞7 转存文件8 评论