催化反应产率预测赛题–Datawhale AI夏令营
赛题概况
背景
碳氮成键反应、Diels-Alder环加成反应等一系列催化合成反应,被广泛应用于各类药物的生产合成中。研究人员与产业界在针对特定反应类型开发新的催化合成方法时,往往追求以高产率获得目标产物,也即开发高活性的催化反应体系,以提升原子经济性,减少资源的浪费与环境污染。然而,开发具有高活性的催化反应体系通常需要对包括催化剂和溶剂在内的多种反应条件进行详尽的探索,这导致了它成为了一项极为耗时且资源密集的任务。这要求对包括催化剂和溶剂在内的多种反应条件进行详尽的探索。目前,反应条件的筛选在很大程度上依赖于经验判断和偶然发现,导致催化反应条件的优化过程既耗时又费力,并且严重制约了新的高效催化合成策略的开发。
反应底物和反应条件是决定其产率的关键因素。因此,我们可以利用AI模型来捕捉底物、条件与产率之间的内在联系。借助产率预测AI模型,仅需输入底物和条件的信息,我们就能够预测该反应组合下的产率,从而有效提升催化反应的条件筛选效率。
数据集概况
数据集仅包含碳氮成键类型反应数据,其中训练集中包含23538条反应数据,测试集中包含2616条反应数据。
rxnid | Reactant1 | Reactant2 | Product | Additive | Solvent | Yield |
---|---|---|---|---|---|---|
train1 | c1ccc2c(c1)Nc1ccccc1O2 | Brc1ccccc1I | Brc1ccccc1N1c2ccccc2Oc2ccccc21 | CC©©[O-].CC©©PH+C©©C.FB-(F)F.FB-(F)F.O=C(C=Cc1ccccc1)C=Cc1ccccc1.O=C(C=Cc1ccccc1)C=Cc1ccccc1.[H+].[Na+].[Pd] | Cc1ccccc1 | 0.78 |
train2 | c1ccc2c(c1)Nc1ccccc1O2 | Brc1ccccc1I | Brc1ccccc1N1c2ccccc2Oc2ccccc21 | C1COCCOCCOCCOCCOCCO1.O=C([O-])[O-].[Cu+].[I-].[K+].[K+]Clc1ccccc1Cl | Clc1ccccc1Cl | 0.90 |
train3 | c1ccc2c(c1)Nc1ccccc1O2 | Brc1ccccc1I | Brc1ccccc1N1c2ccccc2Oc2ccccc21 | CC(=O)[O-].CC(=O)[O-].CC©©[O-].CC©©PH+C©©C.FB-(F)F.FB-(F)F.[H+].[Na+].[Pd+2] | CC1©C=CC=CC1 | 0.85 |
baseline1
基础版
该阶段的处理思路是先使用Morgan分子指纹建模SMILES,将化学语言编码为计算机能够处理的向量形式,再将其输入到随机森林模型中训练,最后在测试集数据上进行预测。关键代码片段如下。
1.生成分子指纹描述符
def mfgen(mol,nBits=2048, radius=2):
fp = rdMolDescriptors.GetMorganFingerprintAsBitVect(mol,radius=radius,nBits=nBits)
return np.array(list(map(eval,list(fp.ToBitString()))))
2.将SMILES序列向量化
def vec_cpd_lst(smi_lst):
smi_set = list(set(smi_lst))
smi_vec_map = {}
for smi in tqdm(smi_set):
mol = Chem.MolFromSmiles(smi)
smi_vec_map[smi] = mfgen(mol)
smi_vec_map[''] = np.zeros(2048)
vec_lst = [smi_vec_map[smi] for smi in smi_lst]
return np.array(vec_lst)
3.随机森林
model = RandomForestRegressor(n_estimators=100,max_depth=10,min_samples_split=2,min_samples_leaf=1,n_jobs=-1)
model.fit(train_x,train_y)
对于该基础模板代码,提交了一份结果,只有0.2034的分数。
在基于机器学习的基础上,改进思路大致往两个方面。
- 运用效果更好的回归算法(改进1、改进2)
- 更换其他编码方式(改进3)
- 数据预处理(改进4)
改进1–LightGBM
将随机森林算法换成了LightGBM。
LightGBM主要通过以下两个方面进行了改进来提升性能:
(1) 直方图算法
LightGBM使用直方图算法来降低计算成本。该算法首先离散连续值,然后以此构建直方图,此后依据遍历样本数据时积聚的量得到最合适的分裂点。相比于其他GBDT算法使用的预排序算法,直方图算法大大降低了时间复杂度,只需要计算次数。
(2) 带深度限制的leaf-wise策略
LightGBM在直方图算法的基础上进一步优化,采用了带深度限制的leaf-wise策略。传统的GBDT工具通常使用按层生长(level-wise)的决策树生长策略,而LightGBM采用了更高效的按叶子生长(leaf-wise)算法。Leaf-wise策略对分割节点的选择是以增益为准的,相比于level-wise策略,leaf-wise有着更低的误差以及更优的效果。以上两种节点分裂方式如下图所示。
对于代码上,只需更换预测部分的模型选择
from lightgbm import LGBMRegressor
import joblib
model = LGBMRegressor(n_estimators=100, max_depth=10, learning_rate=0.1, device="gpu")
model.fit(train_x, train_y)
joblib.dump(model, 'lightgbm_model.pkl')
loaded_model = joblib.load('lightgbm_model.pkl')
test_pred = loaded_model.predict(test_x)
最后的结果是相较基础baseline有少量提升,达到了0.2564。
改进2–XGBoost
XGBoost是对GBDT的一种高效实现,在很多比赛中都有着优秀的表现,故下一步的优化将采用它。
代码部分,同样只需要更换模型即可
from xgboost import XGBRegressor
#model = XGBRegressor(n_estimators=100, max_depth=10, learning_rate=0.1, n_jobs=-1)
model = XGBRegressor(n_estimators=100, max_depth=10, learning_rate=0.1, tree_method='hist',device = "cuda")
model.fit(train_x, train_y)
import joblib
joblib.dump(model, 'xgboost_model.pkl')
loaded_model = joblib.load('xgboost_model.pkl')
test_pred = loaded_model.predict(test_x)
这里有几个参数可以进行调整
- n_estimators:决策树的数量,相对来说越多越好
- max_depth:决策树的最大深度,越深能涵盖更多信息,但是容易过拟合
- learing_rate:学习率
最终通过调参将得分从0.3031提升至0.3442,是目前最好的结果了。
这一部分因为涉及到调参,以及每天3次的提交限制,卡了很多天,但是和头部大佬仍有很大差距,这奖学金就不是我该拿的😇😇😇
改进3–其他编码方式
化学信息学的知识并不是很熟悉,尝试了rdkit库里的其他编码方式,没什么变化???🙄
群里那个改编码方式提升到0.38的,受我一拜🤤
改进4–数据处理
经验而言,两万多的数据大也不大,少也不少,通常可以做一个数据增强。故将训练集扩增了几倍(偷懒没用EDA),但是结果并不好,相较于不用还下降了一丢丢,过拟合了吗???????????