Datawhale AI 夏令营如何跑通第一个baseline以及代码和参数优化

首先,我们先用电脑打开此链接Datawhale进入Datawhale速通手册并用微信登录,左侧栏用于提交最新分数、学习笔记以及打卡,右侧便是速通手册。

 接下来,按照速通手册进行操作,就可以跑通第一个baseline。

将文件提交到比赛官网便可以得到自己的分数,第一次跑通baseline得分在0.2左右。

接下来将讲解提高分数的第一种方法,修改随机森林模型的参数。

原代码 可以调节的参数有:

1. n_estimators

这是随机森林中决策树的数量。通常情况下,增加决策树的数量可以提高模型的稳定性和准确性,但也会增加计算成本。对于大型数据集,通常可以从100开始尝试,然后逐渐增加到几百棵。

2. max_depth

这是单个决策树的最大深度。较深的树可能会导致过拟合,而较浅的树可能无法捕捉到足够的数据模式。我们可以考虑使用一个较大的值,如None(默认值,让树完全生长),或者限制到一个合理的值,比如30。

3. min_samples_split

这是允许节点分裂所需的最小样本数。默认通常是2。对于较大的数据集,可以考虑稍微增加这个值,例如5或10,以减少过拟合的风险。

4. min_samples_leaf

这是叶子节点所需的最小样本数。默认通常是1。对于较大的数据集,可以考虑稍微增加这个值,例如2或4,以减少过拟合的风险。

请注意,

  • 如果发现模型过拟合,可以考虑减少max_depth或者增加min_samples_leaf
  • 如果模型欠拟合,可以尝试增加n_estimators。

调节参数时,决策树的数量越多,树的深度越深,程序运行时间越久,不建议将参数调的过于大。

接下来将讲解提高分数的第二种方法,贝叶斯优化。

以下是完整的步骤:

  1. 安装scikit-optimize库。
  2. 导入必要的库。
  3. 定义一个目标函数,该函数使用随机森林回归器并返回交叉验证得分。
  4. 使用贝叶斯优化搜索超参数空间。
  5. 使用找到的最佳超参数重新训练模型,并进行预测。

下面便是优化后的代码。

!pip install pandas
!pip install -U scikit-learn
!pip install rdkit
!pip install scikit-optimize

import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import cross_val_score
from skopt import BayesSearchCV
from rdkit.Chem import rdMolDescriptors
from rdkit import RDLogger, Chem
from rdkit.Chem import AllChem
import pickle
from tqdm import tqdm
import os

# 禁止RDKit的日志输出
RDLogger.DisableLog('rdApp.*')

# 定义函数以生成分子指纹
def mfgen(mol, nBits=2048, radius=2):
    fp = rdMolDescriptors.GetMorganFingerprintAsBitVect(mol, radius=radius, nBits=nBits)
    return np.array(list(map(int, list(fp.ToBitString()))))

# 加载数据
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)

# 获取数据集路径
dataset_dir = '../dataset'

# 读取训练和测试数据
train_df = pd.read_csv(os.path.join(dataset_dir, 'round1_train_data.csv'))
test_df = pd.read_csv(os.path.join(dataset_dir, 'round1_test_data.csv'))

print(f'Training set size: {len(train_df)}, test set size: {len(test_df)}')

# 从CSV中读取数据
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)

# 拼接指纹向量
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)

# 定义目标函数
def objective(params):
    model = RandomForestRegressor(**params, n_jobs=-1)
    score = -cross_val_score(model, train_x, train_y, cv=5, scoring='neg_mean_squared_error').mean()
    return score

# 定义超参数搜索空间
param_space = {
    'n_estimators': (50, 100),
    'max_depth': (10, 50),
    'min_samples_split': (2, 4),
    'min_samples_leaf': (1, 3),
    'max_features': ('None', 'sqrt', 'log2')
}

# 创建贝叶斯优化器
optimizer = BayesSearchCV(
    estimator=RandomForestRegressor(),
    search_spaces=param_space,
    n_iter=50,
    cv=5,
    scoring='neg_mean_squared_error',
    n_jobs=-1,
    verbose=0
)

# 进行贝叶斯优化
optimizer.fit(train_x, train_y)

# 打印最佳超参数
best_params = optimizer.best_params_
print("Best parameters found:", best_params)

# 使用最佳参数重新训练模型
best_model = RandomForestRegressor(**best_params, n_jobs=-1)
best_model.fit(train_x, train_y)

# 保存模型
with open('./random_forest_model.pkl', 'wb') as file:
    pickle.dump(best_model, file)

# 加载模型
with open('random_forest_model.pkl', 'rb') as file:
    loaded_model = pickle.load(file)

# 预测
test_pred = loaded_model.predict(test_x)

# 格式化预测结果
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.write('\n'.join(ans_str_lst))

请注意这个方法本质上是把搜索空间内的参数全运行一遍,找到最佳参数,因此运行时间非常长。

为了缩短运行时间,我们可以采取几种策略来优化贝叶斯优化的过程。以下是一些建议:

  1. 减少迭代次数 (n_iter): 减少搜索的迭代次数可以显著减少运行时间。
  2. 简化搜索空间: 通过减少搜索空间的范围或选项数量,可以更快地收敛到较好的超参数组合。
  3. 减少交叉验证折叠数 (cv): 减少交叉验证的折叠数也可以减少运行时间,但这可能会增加模型评估的方差。

如果嫌运行时间太长,可以使用第一种方法,直接调参数。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值