当前位置:   article > 正文

Datawhale AI 夏令营 | 物质科学赛道Task1

Datawhale AI 夏令营 | 物质科学赛道Task1

目录

背景知识

比赛任务

赛事数据

数据集

Baseline

评价指标

补充知识

分子指纹

决策树(Decision Trees)

随机森林模型(Random Forest)

baseline解析

准备工作

step1 配置环境

pickle

pandas

tqdm

rdkit

numpy

step2 读取数据并使用Morgan分子指纹建模SMILES

定义mfgen()函数

定义vec_cpd_lst()函数

读取数据并向量化(vectorization)

step3 随机森林模型拟合和保存(训练过程)

step4 answer generation答案生成

思考


本次夏令营以题带练,题目为第二届世界科学智能大赛物质科学赛道:催化反应产率预测。利用历史催化反应数据,并结合AI技术,可以预测新催化反应的产率,从而有效地帮助科研人员和产业界加快高活性反应条件的筛选速度,减少资源与人力的消耗,促进新物质的创造与合成。

背景知识

反应底物和反应条件是决定其产率的关键因素。因此,我们可以利用AI模型来捕捉底物、条件与产率之间的内在联系。借助产率预测AI模型,仅需输入底物和条件的信息,我们就能够预测该反应组合下的产率,从而有效提升催化反应的条件筛选效率。

比赛任务

本次比赛提供在药物合成中常见的多种催化反应实验数据,其中包括反应的底物、包括催化剂在内的反应添加剂、反应溶剂以及反应产物,期待选手通过分析反应数据,利用机器学习、深度学习算法或者大语言模型,建立产率预测模型,从而辅助未知新反应的反应条件筛选。

任务:构建一个能够准确预测碳氮成键反应产率的预测模型

  • 通过对反应中所包含的反应底物、添加剂、溶剂以及产物进行合理的特征化,运用机器学习模型或者深度学习模型拟合预测反应的产率。或者利用训练集数据对开源大语言模型进行微调以预测反应的产率。

赛事数据

数据集

初赛数据集仅包含碳氮成键类型反应数据,其中训练集中包含23538条反应数据,测试集中包含2616条反应数据。训练集与测试集的比例接近9:1。每条训练数据包含 rxnid, Reactant1, Reactant2 , Product , Additive , Solvent , Yield字段。其中 Reactant1 , Reactant2 , Product , Additive , Solvent 字段中为对应物质的SMILES字符串,Yield字段为目标字段,是经过归一化的浮点数。

Baseline

我们提供一个基础的baseline,利用分子指纹对化合物进行编码,并且使用随机森林模型来预测反应的产率。

评价指标

实验真实结果与预测结果R^{2}决定系数来进行评测:

补充知识

本次学习活动的赛题是一个典型的回归问题,机器学习一般分为两种类型的问题:回归问题和分类问题。

回归问题:即预测的结果是连续的值。

分类问题:预测的结果是离散的值。

赛题要求就是建模SMILES式子,然后模型输出到0-1之间的连续值。

分子指纹

分子指纹将分子结构转化为一系列数字或位向量,以此表示分子的结构信息。这些特征通常包括原子和分子的电荷、大小、极性等,旨在刻画分子所具备的一些重要化学特征。

较为常见的输入格式是SMILES化学式表示,使用一些化学信息学软件/库(如RDKit、ChemAxon等)计算分子指纹。

在本项目,采用Morgan指纹表示。关于不同的化学指纹表示方法及其特点可以看Rdkit|化学指纹(fingerprint)

决策树(Decision Trees)

决策树作为机器学习算法中较为简单和常见的算法之一,可以用于解决分类和回归两类问题。

决策树用于分类问题:对于一个数据(数值、图片、视频),对于该数据节点做是非题,判断该数据节点应当向树的哪个方向走,直至叶子节点,得到该数据对应的标号。

决策树用于回归问题:叶节点不再是上述的分类,而是一个具体的实数值。

决策树的优点:①可解释性,可看到数据处理的过程【常用于银行业保险业】;②处理数值型和类别型的特征。

决策树的缺点:①不稳定性(对于数据的噪音不同,树的构建将会不同),可以属于集成学习解决该问题;②数据过于复杂会生成复杂的树,导致过拟合,针对过拟合问题可以把决策树的枝剪掉一些;③大量的判断语句(可能是if else)不容易并行,性能差。

随机森林模型(Random Forest)

随机森林是让决策树稳定的方法。

针对决策树的不稳定性缺点,随机森林模型将训练多个决策树综合得到结果,提升稳定性。

随机森林的随机性(randomness)来自于:①bagging,在训练集随机采样一些样本出来(放回导致可重复性);②在bagging出来的数值中,随机采样一些特征,而并不是全部特征。

baseline解析

准备工作

继续使用魔搭GPU环境,在对应的文件夹添加dataset压缩包。

新建终端并执行下面操作,以解压数据集。

unzip dataset.zip

step1 配置环境

  1. !pip install pandas
  2. !pip install -U scikit-learn
  3. !pip install rdkit

需要安装三个库:pandas(用于数据处理和分析),scikit-learn(机器学习库),rdkit(化学信息工具)。

  1. import pickle
  2. import pandas as pd
  3. from tqdm import tqdm
  4. from sklearn.ensemble import RandomForestRegressor
  5. from rdkit.Chem import rdMolDescriptors
  6. from rdkit import RDLogger,Chem
  7. import numpy as np
  8. RDLogger.DisableLog('rdApp.*') #表示禁用 RDKit 生成的日志消息
pickle

picklePython 库中的一个模块,用于将 Python对象序列化和反序列化。pickle 可以将对象序列化为字符串或字节序列,以便在网络上传输或保存到文件中。

在Saving model to file和Load model from file步骤时,使用了pickle模块的dump方法保存为文件,load方法从文件中加载出来。

pandas

Pandas 库是一个免费、开源的第三方 Python 库,是数据分析常见工具。Datawhale开源教程项目叫 Joyful Pandas 可以学习pandas

tqdm

监测程序运行的进度,估计运行的时长,协助debug。

详细用法可见这篇博客【python第三方库】tqdm——超详细解读

rdkit

化学信息学中主要的工具,开源。网址:http://www.rdkit.org

详细用法可见博客RDkit入门

numpy

官方文档:numpy.org ,这里结合baseline中出现的语句进行介绍。

numpy的核心:ndarray ,数组对象表示固定大小项的多维、同构数组。

生成ndarray的方法有二:numpy.array() 和 numpy.zeros() ,baseline中均有体现

  1. # 返回给定形状和类型的新数组。
  2. numpy.array ( object , dtype = None , * , copy = True , order = 'K', subok = False , ndmin = 0 , like = None )
  3. # 返回给定形状和类型的新数组,并用零填充。
  4. numpy.zeros ( shape, dtype = float, order = 'C', *, like =None )

在向量化时用到concatenate方法,具体参数及解释如下

numpy.concatenate ( (a1, a2, ...), axis=0 ,out=None,dtype =None, casting="same_kind" )

表示沿现有轴连接一系列数组。

step2 读取数据并使用Morgan分子指纹建模SMILES

定义mfgen()函数
  1. def mfgen(mol,nBits=2048, radius=2):
  2. '''
  3. Parameters
  4. ----------
  5. mol : mol
  6. RDKit mol object.
  7. nBits : int
  8. Number of bits for the fingerprint.
  9. radius : int
  10. Radius of the Morgan fingerprint.
  11. Returns
  12. -------
  13. mf_desc_map : ndarray
  14. ndarray of molecular fingerprint descriptors.
  15. '''
  16. fp = rdMolDescriptors.GetMorganFingerprintAsBitVect(mol,radius=radius,nBits=nBits)
  17. return np.array(list(map(eval,list(fp.ToBitString()))))

由三个参数(摩尔值、指纹的位数、指纹的半径)-->返回的是分子指纹描述符阵列

这里使用的是

fp = rdMolDescriptors.GetMorganFingerprintAsBitVect(mol,radius=radius,nBits=nBits)

生成为Morgan指纹,可用于描述分子的结构和相似性,它基于分子的拓扑结构和半径参数生成。

指纹的长度和半径参数可以根据需要进行调整,以平衡指纹的信息量和计算效率。

定义vec_cpd_lst()函数
  1. def vec_cpd_lst(smi_lst):
  2. smi_set = list(set(smi_lst)) #为什么这么操作?
  3. smi_vec_map = {}
  4. # 得到了mol值,调用上面的函数,得到对应分子的分子指纹描述符阵列
  5. #用字典保存{分子smiles表示方式:分子指纹描述符阵列}
  6. for smi in tqdm(smi_set):
  7. # tqdm是进度条模块,tqdm可以让我们在训练过程中看到每个epoch的进度
  8. mol = Chem.MolFromSmiles(smi)
  9. smi_vec_map[smi] = mfgen(mol)
  10. smi_vec_map[''] = np.zeros(2048)
  11. #保存对应的分子指纹阵列的列表推导式
  12. vec_lst = [smi_vec_map[smi] for smi in smi_lst]
  13. return np.array(vec_lst)
读取数据并向量化(vectorization)
  1. dataset_dir = '../dataset' # Change this to your dataset directory
  2. # 读训练集和测试集
  3. train_df = pd.read_csv(f'{dataset_dir}/round1_train_data.csv')
  4. test_df = pd.read_csv(f'{dataset_dir}/round1_test_data.csv')
  5. # 打印出训练集和测试集的size
  6. print(f'Training set size: {len(train_df)}, test set size: {len(test_df)}')

  1. # 提取训练集的反应物1/2、催化剂、溶剂的smiles表示方法
  2. train_rct1_smi = train_df['Reactant1'].to_list()
  3. train_rct2_smi = train_df['Reactant2'].to_list()
  4. train_add_smi = train_df['Additive'].to_list()
  5. train_sol_smi = train_df['Solvent'].to_list()
  6. # 得到分子指纹描述符阵列 fingerprint=fp
  7. train_rct1_fp = vec_cpd_lst(train_rct1_smi)
  8. train_rct2_fp = vec_cpd_lst(train_rct2_smi)
  9. train_add_fp = vec_cpd_lst(train_add_smi)
  10. train_sol_fp = vec_cpd_lst(train_sol_smi)
  11. train_x = np.concatenate([train_rct1_fp,train_rct2_fp,train_add_fp,train_sol_fp],axis=1)
  12. train_y = train_df['Yield'].to_numpy() #将数据转换为一个numpy数组
  13. #将测试集的内容提取出来
  14. test_rct1_smi = test_df['Reactant1'].to_list()
  15. test_rct2_smi = test_df['Reactant2'].to_list()
  16. test_add_smi = test_df['Additive'].to_list()
  17. test_sol_smi = test_df['Solvent'].to_list()
  18. test_rct1_fp = vec_cpd_lst(test_rct1_smi)
  19. test_rct2_fp = vec_cpd_lst(test_rct2_smi)
  20. test_add_fp = vec_cpd_lst(test_add_smi)
  21. test_sol_fp = vec_cpd_lst(test_sol_smi)
  22. test_x = np.concatenate([test_rct1_fp,test_rct2_fp,test_add_fp,test_sol_fp],axis=1)

step3 随机森林模型拟合和保存(训练过程)

model fitting and saving,使用随机森林模型【这里可以调参】

  1. # Model fitting模型拟合
  2. model = RandomForestRegressor(n_estimators=100,max_depth=10,min_samples_split=2,min_samples_leaf=1,n_jobs=-1)
  3. model.fit(train_x,train_y)

参数解释:

  • n_estimators=10: 决策树的个数,越多越好;但是越多意味着计算开销越大;

  • max_depth: (default=None)设置树的最大深度,默认为None;

  • min_samples_split: 根据属性划分节点时,最少的样本数;

  • min_samples_leaf: 叶子节点最少的样本数;

  • n_jobs=1: 并行job个数,-1表示使用所有cpu进行并行计算。

  1. # Saving model to file模型保存为文件
  2. with open('./random_forest_model.pkl', 'wb') as file:
  3. pickle.dump(model, file)
  1. # Load model from file从文件中加载出来模型
  2. with open('random_forest_model.pkl', 'rb') as file:
  3. loaded_model = pickle.load(file)
  1. # Inference预测/推理
  2. test_pred = loaded_model.predict(test_x)

step4 answer generation答案生成

  1. ans_str_lst = ['rxnid,Yield']
  2. for idx,y in enumerate(test_pred):
  3. ans_str_lst.append(f'test{idx+1},{y:.4f}')
  4. with open('./submit.txt','w') as fw:
  5. fw.writelines('\n'.join(ans_str_lst))

格式符合要求。

思考

mfgen()函数:指纹的长度和半径参数可以根据需要进行调整,以平衡指纹的信息量和计算效率。

随机森林模型:决策树的个数和深度可以调参。

参考:datawhale跟李沐学AI

本周还会发布更加深入的分析文章,期待您的点赞、收藏,欢迎讨论交流!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/978127
推荐阅读
相关标签
  

闽ICP备14008679号