自然语言处理领域自从ChatGPT于2022年11月的发布得到了极大的关注,因此2023年也被AI元年。自然语言是人类的母语,而分子,原子也可以说是自然的母语(尽管后续研究探究发现RNN以及transformer,用于处理自然语言,有序数据的较优的模型,在这个根据分子结构预测产率的问题上远不及rf,但GNN被在此类问题上优势很大)。人工智能可以解决两类问题,分类和回归问题,领悟机器学习的核心在于特征工程和方式模型。特征工程在化学领域主要依赖于rdkit库,这是一个开源的化学信息python库,简而言之,分子指纹就是将分子向量化如:
- 拓扑指纹 Chem.RDKFingerprint(mol)
- MACCS 指纹
- Atom Pairs
- topological torsions
- 摩根指纹(圆圈指纹)
- 摩根指纹拓展
- ESTATE指纹(rdkit version 2022.03+)
dc_smiles = data['Smiles']
rdkit_featurizer = dc.feat.RDKitDescriptors()
rdkit_feature = rdkit_featurizer.featurize(dc_smiles)
dc_feature = pd.DataFrame(rdkit_feature)
dc_feature.columns = [f'smiles_dc_{i}' for i in range(dc_feature.shape[1])]
zeros_count = dc_feature.eq(0).sum()
columns_to_drop = zeros_count[zeros_count >= 704].index.tolist()
smiles_feature = dc_feature.drop(columns=columns_to_drop)
最大的好处就是可以使用矩阵的方式包含了分子特征,特征得以提取,其次我们可以定量衡量分子相似性,这没有计算机思维之前是不可能的。化学从萌芽阶段到燃素化学,描述化学从自然语言到化学特有符号,用了3000年,而发展到如今的现代化学,化学的符号得以有简便的输入方法(SMILES),又花费了800年。除此以外,随着计算化学的发展,自然得以与计算机交互。值得注意的是InChi格式,是一种更好的标识远比SMILES所包含的信息更多,并且转换是开源的。以下都是可以使用rdkit对InChi格式所能获得的。
mol = Chem.MolFromInchi(inchi)
# 氢键供体
h_donors = Descriptors.NumHDonors(mol)
# 氢键受体
h_acceptors = Descriptors.NumHAcceptors(mol)
# 旋转键个数
rotatable_bonds = Descriptors.NumRotatableBonds(mol)
# 芳香环数
aromatic_ring_count = Descriptors.NumAromaticRings(mol)
# 总极性表面积 (TPSA)
tpsa = rdMolDescriptors.CalcTPSA(mol)
# XLogP
xlogp = Descriptors.MolLogP(mol)
# 价电子数
num_valence_electrons = Descriptors.NumValenceElectrons(mol)
# 平均信息含量
avg_ipc = GraphDescriptors.AvgIpc(mol)
# Balaban's J
balaban_j = GraphDescriptors.BalabanJ(mol)
# BertzCT 复杂度
bertz_ct = GraphDescriptors.BertzCT(mol)
# 重原子分子量
heavy_atom_mol_wt = Descriptors.HeavyAtomMolWt(mol)
# 最大绝对部分电荷
max_abs_partial_charge = Descriptors.MaxAbsPartialCharge(mol)
# 最大部分电荷
max_partial_charge = Descriptors.MaxPartialCharge(mol)
# 最小绝对部分电荷
min_abs_partial_charge = Descriptors.MinAbsPartialCharge(mol)
# 最小部分电荷
min_partial_charge = Descriptors.MinPartialCharge(mol)
# 分子的Kappa1
kappa1 = rdMolDescriptors.CalcKappa1(mol)
# 分子的Kappa2
kappa2 = rdMolDescriptors.CalcKappa2(mol)
# 分子的Kappa3
kappa3 = rdMolDescriptors.CalcKappa3(mol)
# 分子的Labute ASA
labute_asa = rdMolDescriptors.CalcLabuteASA(mol)
# 分子的Morgan指纹
morgan_fingerprint = rdMolDescriptors.GetMorganFingerprint(mol, 2)
# 分子的自旋轨道耦合常数
kappa = rdMolDescriptors.CalcPhi(mol)
# 分子的饱和碳环数
num_saturated_carbocycles = rdMolDescriptors.CalcNumSaturatedCarbocycles(mol)
# 分子的饱和杂环数
num_saturated_heterocycles = rdMolDescriptors.CalcNumSaturatedHeterocycles(mol)
# 分子的饱和环数
num_saturated_rings = rdMolDescriptors.CalcNumSaturatedRings(mol)
# 分子的螺原子数
num_spiro_atoms = rdMolDescriptors.CalcNumSpiroAtoms(mol)
# 分子的氧化数
rdMolDescriptors.CalcOxidationNumbers(mol)
# 分子的CSP3分数
fraction_csp3 = Lipinski.FractionCSP3(mol)
# 分子的NHOH计数
nhoh_count = Lipinski.NHOHCount(mol)
# 分子的NO计数
no_count = Lipinski.NOCount(mol)
# 分子的异原子数
num_heteroatoms = Lipinski.NumHeteroatoms(mol)
# 分子的非芳香碳环数
num_aliphatic_carbocycles = Lipinski.NumAliphaticCarbocycles(mol)
# 分子的非芳香杂环数
num_aliphatic_heterocycles = Lipinski.NumAliphaticHeterocycles(mol)
# 分子的非芳香环数
num_aliphatic_rings = Lipinski.NumAliphaticRings(mol)
# 分子的芳烃碳环数追求追求追求
num_aromatic_carbocycles = Lipinski.NumAromaticCarbocycles(mol)
# 分子的芳烃杂环数
num_aromatic_heterocycles = Lipinski.NumAromaticHeterocycles(mol)
# 分子的摩尔折射率
mol_refractivity = Descriptors.MolMR(mol)
可以看见InChi格式的优势很多,更适合rf学习,在仅以SMILES单一指纹向量化的rf模型中深度的影响大于决策树的数量,可见有必要引入更多的描述符,发挥集成学习的优势。 多指纹和InChI化是主要的策略。如下就是InChI化,再配合上述
from rdkit import Chem
# SMILES字符串
smiles = "CC(=O)OC1=CC=CC=C1C(=O)O"
# 将SMILES转化为分子对象
mol = Chem.MolFromSmiles(smiles)
# 将分子对象转化为InChI字符串
inchi = Chem.MolToInchi(mol)
print(inchi)
最初的计算化学主要依托于第一性原理,归根到底是根据近似方法计算单分子计算波函数,由此能得到分子的信息,已知的与未知的, 对于复杂的构效关系,多对象系统,复杂度增加,继续追求精准性是不理智的。这样的问题,往往能够根据经验判断得出部分,这正是人类的优势,而机器学习更是无限接近人脑在处理这样的问题上的潜能。 所谓的经验判断都可以拆分为一系列决定,尽管日常的决策都十分简单且只需若干判断即可,这分别决策树的分支和深度,除此以外,不同人的判断不同,考虑多个人一起判断就是集成学习,最普适的案例就是随机深林算法。
from sklearn.ensemble import RandomForestRegressor
model = RandomForestRegressor(n_estimators=30,max_depth=40,min_samples_split=2,min_samples_leaf=1,n_jobs=-1)
model.fit(train_x,train_y)
predictions = model.predict(train_x)
在skleran库的辅助下搭建这样原理的随机森林也十分轻松。 --未完