Datawhale 夏令营第三期 机器学习 笔记1

  • Datawhale 夏令营第三期 机器学习 笔记1

    • 比赛题目

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

    • 数据

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

    • 赛题类型

      • 回归问题

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

      • ps:

        • 机器学习一般分为两种类型的问题:回归问题和分类问题。

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

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

    • 评审规则

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

    • baseline代码

  • !pip install pandas
    !pip install -U scikit-learn
    !pip install rdkit
    
    # 首先,导入库
    import pickle
    import pandas as pd
    from tqdm import tqdm
    from sklearn.ensemble import RandomForestRegressor
    from rdkit.Chem import rdMolDescriptors
    from rdkit import RDLogger,Chem
    import numpy as np
    from sklearn.model_selection import cross_val_score
    RDLogger.DisableLog('rdApp.*')
    
    #将数据转为向量形式
    def mfgen(mol,nBits=2048, radius=2):
        '''
        Parameters
        ----------
        mol : mol
            RDKit mol object.
        nBits : int
            Number of bits for the fingerprint.
        radius : int
            Radius of the Morgan fingerprint.
        Returns
        -------
        mf_desc_map : ndarray
            ndarray of molecular fingerprint descriptors.
        '''
        # 返回分子的位向量形式的Morgan fingerprint
        fp = rdMolDescriptors.GetMorganFingerprintAsBitVect(mol,radius=radius,nBits=nBits)
        return np.array(list(map(eval,list(fp.ToBitString()))))
    
    # 加载数据
    def vec_cpd_lst(smi_lst):
        smi_set = list(set(smi_lst))
        smi_vec_map = {}
        for smi in tqdm(smi_set): # tqdm:显示进度条
            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)
    
    #从文件读取数据
    dataset_dir = '../dataset'   # # 注:如果是在AI Studio上,将这里改为'dataset'
    
    train_df = pd.read_csv(f'{dataset_dir}/round1_train_data.csv')
    test_df = pd.read_csv(f'{dataset_dir}/round1_test_data.csv')
    
    print(f'Training set size: {len(train_df)}, test set size: {len(test_df)}')
    
    # 从df中读取数据
    train_rct1_smi = train_df['Reactant1'].to_list()
    train_rct2_smi = train_df['Reactant2'].to_list()
    train_add_smi = train_df['Additive'].to_list()
    train_sol_smi = train_df['Solvent'].to_list()
    
    # 将SMILES转化为分子指纹
    train_rct1_fp = vec_cpd_lst(train_rct1_smi)
    train_rct2_fp = vec_cpd_lst(train_rct2_smi)
    train_add_fp = vec_cpd_lst(train_add_smi)
    train_sol_fp = vec_cpd_lst(train_sol_smi)
    # 在dim=1维度进行拼接。即:将一条数据的Reactant1,Reactant2,Product,Additive,Solvent字段的morgan fingerprint拼接为一个向量。
    train_x = np.concatenate([train_rct1_fp,train_rct2_fp,train_add_fp,train_sol_fp],axis=1)
    train_y = train_df['Yield'].to_numpy()
    
    # 测试集也进行同样的操作
    test_rct1_smi = test_df['Reactant1'].to_list()
    test_rct2_smi = test_df['Reactant2'].to_list()
    test_add_smi = test_df['Additive'].to_list()
    test_sol_smi = test_df['Solvent'].to_list()
    
    test_rct1_fp = vec_cpd_lst(test_rct1_smi)
    test_rct2_fp = vec_cpd_lst(test_rct2_smi)
    test_add_fp = vec_cpd_lst(test_add_smi)
    test_sol_fp = vec_cpd_lst(test_sol_smi)
    test_x = np.concatenate([test_rct1_fp,test_rct2_fp,test_add_fp,test_sol_fp],axis=1)
    
    #训练模型
    # Model fitting
    model = RandomForestRegressor(n_estimators=100,min_samples_split=2,min_samples_leaf=1,n_jobs=-1) # 实例化模型,并指定重要参数
    model.fit(train_x,train_y) # 训练模型
    
    # 保存模型
    with open('./random_forest_model.pkl', 'wb') as file:
        pickle.dump(model, file)
    
    # 加载模型
    with open('random_forest_model.pkl', 'rb') as file:
        loaded_model = pickle.load(file)
    
    # 预测\推理
    test_pred = loaded_model.predict(test_x)
    
    # 交叉验证
    accuracy_score = cross_val_score(model, train_x, train_y)
    print(accuracy_score)
    
    #生成赛题要求的结果文件
    ans_str_lst = ['rxnid,Yield']
    for idx,y in enumerate(test_pred):
        ans_str_lst.append(f'test{idx+1},{y:.4f}')
    with open('./submit.txt','w') as fw:
        fw.writelines('\n'.join(ans_str_lst))

  • 提交结果

    • (1)第一次直接提交baseline的运行结果,什么也没改,得分如下:

      日期:2024-07-26 09:57:39

      分数:0.1985

    • 结果分析:树个数为10,深度为10,由于树是按照特征不断进行划分的,深度为10的划分对分类不够全面。另外随机森林是群体决策,树个数过少影响精度。

    • (2)第二次将随机森林的个数改为100个,深度改为默认none,得分如下:

      日期:2024-07-27 23:14:34

      分数:0.3367

    • 结果分析:增加树的个数和深度后,分数显著提升。经查找资料,一般通过交叉验证来确定最佳参数组合,是后续的优化方向。

    • (3)第三次通过多次交叉验证比较

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值