【AI for Science】量子化学:分子属性预测-第1次打卡-机器学习baseline

简介: 【AI for Science】量子化学:分子属性预测-第1次打卡-机器学习baseline


1. 赛题

1.1 赛事背景

宏观世界是由大量的微观粒子组成,了解微观粒子的运动和性质,才能更好的认识宏观世界。借助计算机模拟技术和量子力学的基本原理,量子化学计算应运而生,从电子层面阐明分子的能量、性质以及分子间相互作用的本质。量子化学计算在生物、化学、医药和材料科学等领域中具有广泛应用,例如:预测化学反应的热化学性质、分析分子的光谱学特性、优化材料的物理性质等。然而,量子化学计算存在计算量大、成本昂贵、耗时长等缺点,这限制了其在科学研究和技术创新领域的进一步发展。

为了推动量子化学与基础科学研究的深度融合,我们需要积极探索计算成本更低、更高效的求解方法,为此发起了本届 《量子化学分子属性预测大赛》。本次大赛中,我们开源了国内首个采用高精度QM方法计算的分子构象数据集,其中包含了12万个分子和1000多万个构象。这些分子的构象包括了旋转、振动、弯曲等不同形式的构象,覆盖了多种不同的单分子性质,具有高精度、高可靠性和高实用性等特点,能够为参赛者提供准确、丰富和具有代表性的数据资源。

此外,我们还会提供详细的数据集说明和相关文献,帮助参赛者更好地理解和使用这个数据集,从而更好地完成赛题任务。我们相信这个数据集的开源将促进量子化学计算领域的进一步发展和应用,也将为更广泛的科学研究和工程实践提供更多的可能性和机会。

1.2 赛事任务

本届赛题为 图属性回归 问题,目标是预测不同构象下分子的 总能量和力 两种性质。数据集将包含一系列分子的构象和量子化学计算得到的能量、力等属性信息,参赛者需要从中选择合适的特征,并使用适当的算法来建立预测模型,快速准确的预测分子的属性。

1.3 赛题数据集

初赛提供训练集数据文件 ,其中包含约500w训练样本。

单个分子中各字段说明如下:

1.4 评价指标

初赛阶段,选手仅需要提交结果文件,只采用准确率进行评分。

复赛阶段,选手的评分将在准确率的基础上考虑同时计算效率

2. 环境配置

阿里云机器学习Pai-DSW服务器部署教程

阿里云平台选择机器学习平台PAI(新用户可免费试用3个月),GPU选择30G的A10.

创建并打开实例后的页面:

然后用 Ossutil命令 完成赛题数据下载。

3. baseline

本题初赛任务是预测能量和力,属于回归问题,不过输入数据比较复杂,给出了原子之间的关系和坐标位置,可以构建空间结构。

模型方面可以选择机器学习模型图神经网络模型,如果使用类似xgboost这类机器学习模型,无法深入挖掘图结构信息,仅能提取简单的图信息,如出度入读、边数量等。如果选择图神经网络模型,则能够有效挖掘图结构信息。

鉴于上面的对比,baseline选择使用机器学习方法

3.1 导入模块

导入我们本次Baseline代码所需的模块

# 导入numpy库,用于进行数值计算
import numpy as np
# 导入pandas库,用于数据处理和分析
import pandas as pd
# 导入polars库,用于处理大规模数据集
import polars as pl
# 导入collections库中的defaultdict和Counter,用于统计
from collections import defaultdict, Counter
# 导入CatBoostRegressor库,用于梯度提升树模型
from catboost import CatBoostRegressor
# 导入StratifiedKFold、KFold和GroupKFold,用于交叉验证
from sklearn.model_selection import StratifiedKFold, KFold, GroupKFold
# 使用Joblib中的Parallel和delayed实现并行化处理
from joblib import Parallel, delayed
# 导入sys、os、gc、argparse和warnings库,用于处理命令行参数和警告信息
import sys, os, gc, argparse, warnings, tqdm
# 均绝对误差)是一个用于回归问题评估模型性能的指标之一,它衡量了预测值与实际观测值之间的平均绝对差异。
from sklearn.metrics import mean_absolute_error
# 忽略警告信息
warnings.filterwarnings('ignore')

3.2 加载数据

path = '..'
test0 = np.load(f'{path}/QMB_round1_test_230725_0.npy', allow_pickle=True).tolist()
test1 = np.load(f'{path}/QMB_round1_test_230725_1.npy', allow_pickle=True).tolist()
test = test0 + test1
del test0, test1
#一个训练集加载后大概20G,根据自己的算力情况选择性加载,baseline采用A10,30G内存的环境,只加载一个训练集
train0 = np.load(f'{path}/QMB_round1_train_230725_0.npy', allow_pickle=True).tolist()
# train1 = np.load(f'{path}/QMB_round1_train_230725_1.npy', allow_pickle=True).tolist()
# train2 = np.load(f'{path}/QMB_round1_train_230725_2.npy', allow_pickle=True).tolist()
# train3 = np.load(f'{path}/QMB_round1_train_230725_3.npy', allow_pickle=True).tolist()
# train4 = np.load(f'{path}/QMB_round1_train_230725_4.npy', allow_pickle=True).tolist()
# train = train0 + train1 + train2 + train3 + train4
# del train0, train1, train2, train3, train4
train = train0
del train0

✏️ 赛题数据解压之后是 npy文件,是 numpy 专用的二进制文件,加载方式:

import numpy as np
data = np.load('data\\x.npy')

3.3 特征工程

特征工程指的是把原始数据转变为模型训练数据的过程,目的是获取更好的训练数据特征。特征工程能使得模型的性能得到提升,有时甚至在简单的模型上也能取得不错的效果。

对逐个样本进行特征提取,connectivity提取相连原子组成的列表的最长和最大统计、edge_list提取最大出度和入度、coordinates坐标位置的均值、最大值、最小值、elements的不同元素数、formal_charge最大值和最小值、edge_attr键类型占比数等。

为了加快运行速度,这里使用Joblib中的Parallel和delayed实现并行化处理,执行get_parallel_feature函数,代码如下:

注:n_jobs为开启的进程数,即是用n_jobs个CPU来计算。

import stats
def get_parallel_feature(data, IS_TRAIN=False):
    # 相连原子组成的列表的最长和最大统计
    max_len = len(max(data['connectivity'], key=len))
    min_len = len(min(data['connectivity'], key=len))
    # 提取最大出度和入度,以及边的数量
    # max_out_degree = stats.mode(data['edge_list'][:,0])[1][0]
    # max_in_degree = stats.mode(data['edge_list'][:,1])[1][0]
    edge_list_len = len(data['edge_list'])
    # 坐标位置的均值、最大值、最小值
    coordinates = data['coordinates'].mean(axis=0).tolist() + \
                  data['coordinates'].max(axis=0).tolist() + \
                  data['coordinates'].min(axis=0).tolist()
    # elements的不同元素数
    elements_nunique = len(set(data['elements']))
    elements = ' '.join([str(i) for i in data['elements']])
    # formal_charge最大值和均值
    formal_charge = [data['formal_charge'].max(), data['formal_charge'].mean()]
    # edge_attr键类型占比数
    edge_attr_1_ratio = len(np.where(np.array(data['edge_attr'])=='1')[0]) / edge_list_len
    edge_attr_2_ratio = len(np.where(np.array(data['edge_attr'])=='2')[0]) / edge_list_len
    edge_attr_3_ratio = len(np.where(np.array(data['edge_attr'])=='3')[0]) / edge_list_len
    edge_attr_nunique = len(set(data['edge_attr']))
    # 合并到一个list中
    res = [data['mol_name'], data['atom_count'], data['bond_count'], max_len, min_len, edge_list_len] + \
           coordinates + [elements_nunique, elements] + formal_charge + \
          [edge_attr_1_ratio, edge_attr_2_ratio, edge_attr_3_ratio, edge_attr_nunique]
    # 返回结果
    if IS_TRAIN:
        return res + [data['energy']]
    else:
        return res
### 测试数据       
test_samples = Parallel(n_jobs=40)(
    delayed(get_parallel_feature)(data, False)
      for data in tqdm.tqdm(test)
)
test_df = pd.DataFrame(test_samples, columns=['mol_name','atom_count','bond_count','maxlen','maxin','edgelen',\
                      'mean1','mean2','mean3','max1','max2','max3','min1','min2','min3','elements_nunique','elements',\
                      'formal_charge_max','formal_charge_min','edge_attr_1_ratio','edge_attr_2_ratio','edge_attr_3_ratio',\
                      'edge_attr_nunique'])
### 训练数据
train_samples = Parallel(n_jobs=40)(
    delayed(get_parallel_feature)(data, True)
      for data in tqdm.tqdm(train)
)
train_df = pd.DataFrame(train_samples, columns=['mol_name','atom_count','bond_count','maxlen','minlen','edgelen',\
                      'mean1','mean2','mean3','max1','max2','max3','min1','min2','min3','elements_nunique','elements',\
                      'formal_charge_max','formal_charge_min','edge_attr_1_ratio','edge_attr_2_ratio','edge_attr_3_ratio',\
                      'edge_attr_nunique','energy'])

构建TfidfVectorizer和CountVectorizer特征,提取elements中的相关信息,代码如下:

from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
def tfidf(data, seqs):
    tfidf = TfidfVectorizer(max_df = 0.95, min_df = 3)
    res = tfidf.fit_transform(data[seqs])
    res = res.toarray()
    for i in range(len(res[0])):
        data['{}_tfidf_{}'.format(seqs,str(i))] = res[:,i]
    gc.collect()
    return data
def CVec(data, seqs):
    tfidf = CountVectorizer(max_df = 0.95, min_df = 3)
    res = tfidf.fit_transform(data[seqs])
    res = res.toarray()
    for i in range(len(res[0])):
        data['{}_cv_{}'.format(seqs,str(i))] = res[:,i]
    gc.collect()
    return data
### 合并训练数据和测试数据
test_df['istest'] = 1
train_df['istest'] = 0
df = pd.concat([test_df, train_df], axis=0, ignore_index=True)
### 进行Tfidf 和 Count
df = tfidf(df, 'elements')
df = CVec(df, 'elements')
### 切分训练数据和测试数据
test_df = df[df.istest==1].reset_index(drop=True)
train_df = df[df.istest==0].reset_index(drop=True)

✏️ CountVectorizer类:

将文本中的词语转换为词频矩阵。也就是通过分词后将所有的文档中的全部词作为一个字典(就是类似于新华字典这种)。然后将每一行的词用0,1矩阵来表示。并且每一行的长度相同,长度为字典的长度,在词典中存在,置为1,否则,为0。

参数:

input: 一般使用默认即可,可以设置为"filename’或’file’;

encodeing: 使用默认的utf-8即可,分析器将会以utf-8解码raw document;

decode_error: 默认为strict,遇到不能解码的字符将报UnicodeDecodeError错误,设为ignore将会忽略解码错误,还可以设为replace,作用尚不明确;

strip_accents: 默认为None,可设为ascii或unicode,将使用ascii或unicode编码在预处理步骤去除raw document中的重音符号;

analyzer: 一般使用默认,可设置为string类型,如’word’, ‘char’, ‘char_wb’,还可设置为callable类型,比如函数是一个callable类型;

preprocessor: 设为None或callable类型;

tokenizer: 设为None或callable类型;

ngram_range: 词组切分的长度范围;

stop_words: 设置停用词,设为english将使用内置的英语停用词,设为一个list可自定义停用词,设为None不使用停用词,设为None且max_df∈[0.7, 1.0)将自动根据当前的语料库建立停用词表;

lowercase: 将所有字符变成小写;

token_pattern: 表示token的正则表达式,需要设置analyzer == ‘word’,默认的正则表达式选择2个及以上的字母或数字作为token,标点符号默认当作token分隔符,而不会被当作token;

max_df: 可以设置为范围在[0.0 1.0]的float,也可以设置为没有范围限制的int,默认为1.0。这个参数的作用是作为一个阈值,当构造语料库的关键词集的时候,如果某个词的document frequence大于max_df,这个词不会被当作关键词。如果这个参数是float,则表示词出现的次数与语料库文档数的百分比,如果是int,则表示词出现的次数。如果参数中已经给定了vocabulary,则这个参数无效;

min_df: 类似于max_df,不同之处在于如果某个词的document frequence小于min_df,则这个词不会被当作关键词;

max_features: 默认为None,可设为int,对所有关键词的term frequency进行降序排序,只取前max_features个作为关键词集;

vocabulary: 默认为None,自动从输入文档中构建关键词集,也可以是一个字典或可迭代对象;

binary: 默认为False,一个关键词在一篇文档中可能出现n次,如果binary=True,非零的n将全部置为1,这对需要布尔值输入的离散概率模型的有用的;

dtype: 使用CountVectorizer类的fit_transform()或transform()将得到一个文档词频矩阵,dtype可以设置这个矩阵的数值类型。

TfidfVectorizer类:

与CountVectorizer有很多相同的参数,下面只解释不同的参数:

binary: 默认为False,tf-idf中每个词的权值是tfidf,如果binary设为True,所有出现的词的tf将置为1,TfidfVectorizer计算得到的tf与CountVectorizer得到的tf是一样的,就是词频,不是词频/该词所在文档的总词数;

norm: 默认为’l2’,可设为’l1’或None,计算得到tf-idf值后,如果norm=‘l2’,则整行权值将归一化,即整行权值向量为单位向量,如果norm=None,则不会进行归一化。大多数情况下,使用归一化是有必要的;

use_idf: 默认为True,权值是tfidf,如果设为False,将不使用idf,就是只使用tf,相当于CountVectorizer了;

smooth_idf: idf平滑参数,默认为True,idf=ln((文档总数+1)/(包含该词的文档数+1))+1,如果设为False,idf=ln(文档总数/包含该词的文档数)+1;

sublinear_tf: 默认为False,如果设为True,则替换tf为1 + log(tf)。

CountVectorizer类和TfidfVectorizer类

3.4 模型训练与验证

特征工程也好,数据清洗也罢,都是为最终的模型来服务的,模型的建立和调参决定了最终的结果。模型的选择决定结果的上限, 如何更好的去达到模型上限取决于模型的调参。

建模的过程需要我们对常见的线性模型、非线性模型有基础的了解。模型构建完成后,需要掌握一定的模型性能验证的方法和技巧。

作为baseline方案使用 catboost 模型,并选择经典的K折交叉验证方法进行离线评估,大体流程如下:

1、K折交叉验证会把样本数据随机的分成K份;

2、每次随机的选择K-1份作为训练集,剩下的1份做验证集;

3、当这一轮完成后,重新随机选择K-1份来训练数据;

4、最后将K折预测结果取平均作为最终提交结果。

具体代码如下:

def catboost_model(train_x, train_y, test_x, seed = 2023):
    folds = 5
    kf = KFold(n_splits=folds, shuffle=True, random_state=seed)
    oof = np.zeros(train_x.shape[0])
    test_predict = np.zeros(test_x.shape[0])
    cv_scores = []
    for i, (train_index, valid_index) in enumerate(kf.split(train_x, train_y)):
        print('************************************ {} ************************************'.format(str(i+1)))
        trn_x, trn_y, val_x, val_y = train_x.iloc[train_index], train_y[train_index], train_x.iloc[valid_index], train_y[valid_index]
        params = {'learning_rate': 0.1, 
                  'depth': 6, 
                  'bootstrap_type':'Bernoulli',
                  'random_seed':2023,
                  'od_type': 'Iter', 
                  'od_wait': 200, 
                  'random_seed': 11, 
                  'allow_writing_files': False,       
                  'task_type':"GPU",  # 任务类型,表示模型运行在GPU还是CPU上。设置为"GPU"表示模型运行在GPU上,如果计算机没有GPU,可以设置为"CPU"。
                  'devices':'0:1'}
        #iterations是迭代次数,可以根据自己的算力配置与精力调整
        model = CatBoostRegressor(iterations=10000, **params)
        model.fit(trn_x, trn_y, eval_set=(val_x, val_y),
                  metric_period=500,
                  use_best_model=True, 
                  cat_features=[],
                  verbose=1)
        val_pred  = model.predict(val_x)
        test_pred = model.predict(test_x)
        oof[valid_index] = val_pred
        test_predict += test_pred / kf.n_splits
        score = mean_absolute_error(val_y, val_pred)
        cv_scores.append(score)
        print(cv_scores)
        # 获取特征重要性打分,便于评估特征
        if i == 0:
            fea_ = model.feature_importances_
            fea_name = model.feature_names_
            fea_score = pd.DataFrame({'fea_name':fea_name, 'score':fea_})
            fea_score = fea_score.sort_values('score', ascending=False)
            fea_score.to_csv('feature_importances.csv', index=False)
    return oof, test_predict
cols = [f for f in test_df.columns if f not in ['elements','energy','mol_name','elements','istest']]
cat_oof, cat_test = catboost_model(train_df[cols], train_df['energy'], test_df[cols])

生成 feature_importances.csv 文件

特征重要性结果展示:

观察特征重要性排序,我们手动构建的elements相关特征重要性排在前面,这也大概率说明这类特征可能有比较大的作用。

3.5 结果输出

提交需要符合提交样例结果,线上提交分数20000+,能优化的空间还是非常大的。特别注意因为force的真实结果非常低,所影响的误差也比较少,所以统一用0作为预测结果。

# 输出赛题提交格式的结果
test_df['energy'] = cat_test
test_df['force'] = test_df['atom_count'].apply(lambda x: ','.join(['0.0' for _ in range(x*3)]))
test_df[['energy','force']].to_csv("submission.csv", index=True)

4. 我的代码

把 CatBoost 模型换成 LightGBM 模型

LightGBM 模型用法参考:

LightGBM回归预测模型构建 - 含GBM调参方法

lightgbm回归模型使用方法(lgbm.LGBMRegressor)

机器学习:lightgbm(实战:分类&&回归)

LightGBM 简单实现

4.1 安装 lightgbm

# !pip install lightgbm
import lightgbm as lgb

4.2 导入模块

# 导入numpy库,用于进行数值计算
import numpy as np
# 导入pandas库,用于数据处理和分析
import pandas as pd
# 导入polars库,用于处理大规模数据集
import polars as pl
# 导入collections库中的defaultdict和Counter,用于统计
from collections import defaultdict, Counter
# 导入LGBMRegressor
from lightgbm import LGBMRegressor
# 导入StratifiedKFold、KFold和GroupKFold,用于交叉验证
from sklearn.model_selection import StratifiedKFold, KFold, GroupKFold
# 使用Joblib中的Parallel和delayed实现并行化处理
from joblib import Parallel, delayed
# 导入sys、os、gc、argparse和warnings库,用于处理命令行参数和警告信息
import sys, os, gc, argparse, warnings, tqdm
# 均绝对误差)是一个用于回归问题评估模型性能的指标之一,它衡量了预测值与实际观测值之间的平均绝对差异。
from sklearn.metrics import mean_absolute_error
# 忽略警告信息
warnings.filterwarnings('ignore')

4.3 加载数据

path = 'data'
test0 = np.load(f'{path}/QMB_round1_test_230725_0.npy', allow_pickle=True).tolist()
test1 = np.load(f'{path}/QMB_round1_test_230725_1.npy', allow_pickle=True).tolist()
test = test0 + test1
del test0, test1
#一个训练集加载后大概20G,根据自己的算力情况选择性加载,baseline采用A10,30G内存的环境,只加载一个训练集
train0 = np.load(f'{path}/QMB_round1_train_230725_0.npy', allow_pickle=True).tolist()
# train1 = np.load(f'{path}/QMB_round1_train_230725_1.npy', allow_pickle=True).tolist()
# train2 = np.load(f'{path}/QMB_round1_train_230725_2.npy', allow_pickle=True).tolist()
# train3 = np.load(f'{path}/QMB_round1_train_230725_3.npy', allow_pickle=True).tolist()
# train4 = np.load(f'{path}/QMB_round1_train_230725_4.npy', allow_pickle=True).tolist()
# train = train0 + train1 + train2 + train3 + train4
# del train0, train1, train2, train3, train4
train = train0
del train0

4.4 特征工程

import stats
def get_parallel_feature(data, IS_TRAIN=False):
    # 相连原子组成的列表的最长和最大统计
    max_len = len(max(data['connectivity'], key=len))
    min_len = len(min(data['connectivity'], key=len))
    # 提取最大出度和入度,以及边的数量
    # max_out_degree = stats.mode(data['edge_list'][:,0])[1][0]
    # max_in_degree = stats.mode(data['edge_list'][:,1])[1][0]
    edge_list_len = len(data['edge_list'])
    # 坐标位置的均值、最大值、最小值
    coordinates = data['coordinates'].mean(axis=0).tolist() + \
                  data['coordinates'].max(axis=0).tolist() + \
                  data['coordinates'].min(axis=0).tolist()
    # elements的不同元素数
    elements_nunique = len(set(data['elements']))
    elements = ' '.join([str(i) for i in data['elements']])
    # formal_charge最大值和最小值
    formal_charge = [data['formal_charge'].max(), data['formal_charge'].mean()]
    # edge_attr键类型占比数
    edge_attr_1_ratio = len(np.where(np.array(data['edge_attr'])=='1')[0]) / edge_list_len
    edge_attr_2_ratio = len(np.where(np.array(data['edge_attr'])=='2')[0]) / edge_list_len
    edge_attr_3_ratio = len(np.where(np.array(data['edge_attr'])=='3')[0]) / edge_list_len
    edge_attr_nunique = len(set(data['edge_attr']))
    # 合并到一个list中
    res = [data['mol_name'], data['atom_count'], data['bond_count'], max_len, min_len, edge_list_len] + \
           coordinates + [elements_nunique, elements] + formal_charge + \
          [edge_attr_1_ratio, edge_attr_2_ratio, edge_attr_3_ratio, edge_attr_nunique]
    # 返回结果
    if IS_TRAIN:
        return res + [data['energy']]
    else:
        return res
### 测试数据       
test_samples = Parallel(n_jobs=40)(
    delayed(get_parallel_feature)(data, False)
      for data in tqdm.tqdm(test)
)
test_df = pd.DataFrame(test_samples, columns=['mol_name','atom_count','bond_count','maxlen','maxin','edgelen',\
                      'mean1','mean2','mean3','max1','max2','max3','min1','min2','min3','elements_nunique','elements',\
                      'formal_charge_max','formal_charge_min','edge_attr_1_ratio','edge_attr_2_ratio','edge_attr_3_ratio',\
                      'edge_attr_nunique'])
### 训练数据
train_samples = Parallel(n_jobs=40)(
    delayed(get_parallel_feature)(data, True)
      for data in tqdm.tqdm(train)
)
train_df = pd.DataFrame(train_samples, columns=['mol_name','atom_count','bond_count','maxlen','minlen','edgelen',\
                      'mean1','mean2','mean3','max1','max2','max3','min1','min2','min3','elements_nunique','elements',\
                      'formal_charge_max','formal_charge_min','edge_attr_1_ratio','edge_attr_2_ratio','edge_attr_3_ratio',\
                      'edge_attr_nunique','energy'])
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
def tfidf(data, seqs):
    tfidf = TfidfVectorizer(max_df = 0.95, min_df = 4)
    res = tfidf.fit_transform(data[seqs])
    res = res.toarray()
    for i in range(len(res[0])):
        data['{}_tfidf_{}'.format(seqs,str(i))] = res[:,i]
    gc.collect()
    return data
def CVec(data, seqs):
    tfidf = CountVectorizer(max_df = 0.95, min_df = 4)
    res = tfidf.fit_transform(data[seqs])
    res = res.toarray()
    for i in range(len(res[0])):
        data['{}_cv_{}'.format(seqs,str(i))] = res[:,i]
    gc.collect()
    return data
### 合并训练数据和测试数据
test_df['istest'] = 1
train_df['istest'] = 0
df = pd.concat([test_df, train_df], axis=0, ignore_index=True)
### 进行Tfidf 和 Count
df = tfidf(df, 'elements')
df = CVec(df, 'elements')
### 切分训练数据和测试数据
test_df = df[df.istest==1].reset_index(drop=True)
train_df = df[df.istest==0].reset_index(drop=True)

4.5 模型训练与验证

# LGBMRegressor: 调用Scikit-learn接口的回归
def lgb_model(train_x, train_y, test_x, seed = 2023):
    folds = 5
    kf = KFold(n_splits=folds, shuffle=True, random_state=seed)
    oof = np.zeros(train_x.shape[0])
    test_predict = np.zeros(test_x.shape[0])
    cv_scores = []
    for i, (train_index, valid_index) in enumerate(kf.split(train_x, train_y)):
        print('************************************ {} ************************************'.format(str(i+1)))
        trn_x, trn_y, val_x, val_y = train_x.iloc[train_index], train_y[train_index], train_x.iloc[valid_index], train_y[valid_index]
        model = lgb.LGBMRegressor(objective='regression', 
                                  num_leaves=500, 
                                  learning_rate=0.01, 
                                  n_estimators=600)
        model.fit(trn_x, trn_y, eval_set=(val_x, val_y))
        val_pred  = model.predict(val_x)
        test_pred = model.predict(test_x)
        oof[valid_index] = val_pred
        test_predict += test_pred / kf.n_splits
        score = mean_absolute_error(val_y, val_pred)
        cv_scores.append(score)
        print(cv_scores)
    return oof, test_predict
cols = [f for f in test_df.columns if f not in ['elements','energy','mol_name','elements','istest']]
cat_oof, cat_test = lgb_model(train_df[cols], train_df['energy'], test_df[cols])

4.6 结果输出

# 输出赛题提交格式的结果
test_df['energy'] = cat_test
test_df['force'] = test_df['atom_count'].apply(lambda x: ','.join(['0.0' for _ in range(x*3)]))
test_df[['energy','force']].to_csv("submission4.csv", index=True)

5. 运行结果

照着 baseline 跑一遍,分数:20773.6846

微调了一下参数(learning_rate调小,depth调大),把 train0 换成 train1 ,之后分数:21879.9301

后面把 CatBoost 模型换成 LightGBM 模型,分数:21249.8966

迭代次数加大之后,分数:21745.3668

还有很大的优化空间。

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
相关文章
|
8天前
|
机器学习/深度学习 人工智能 安全
探索AI的未来:从机器学习到深度学习
【10月更文挑战第28天】本文将带你走进AI的世界,从机器学习的基本概念到深度学习的复杂应用,我们将一起探索AI的未来。你将了解到AI如何改变我们的生活,以及它在未来可能带来的影响。无论你是AI专家还是初学者,这篇文章都将为你提供新的视角和思考。让我们一起探索AI的奥秘,看看它将如何塑造我们的未来。
36 3
|
1月前
|
机器学习/深度学习 数据采集 人工智能
AI与机器学习:从理论到实践
【10月更文挑战第2天】本文将深入探讨AI和机器学习的基本概念,以及它们如何从理论转化为实际的应用。我们将通过Python代码示例,展示如何使用机器学习库scikit-learn进行数据预处理、模型训练和预测。无论你是AI领域的初学者,还是有一定基础的开发者,这篇文章都将为你提供有价值的信息和知识。
|
3天前
|
机器学习/深度学习 人工智能 自然语言处理
机器学习之解释性AI与可解释性机器学习
随着人工智能技术的广泛应用,机器学习模型越来越多地被用于决策过程。然而,这些模型,尤其是深度学习模型,通常被视为“黑箱”,难以理解其背后的决策逻辑。解释性AI(Explainable AI, XAI)和可解释性机器学习(Interpretable Machine Learning, IML)旨在解决这个问题,使模型的决策过程透明、可信。
14 2
|
3天前
|
机器学习/深度学习 数据采集 人工智能
揭秘AI:机器学习的魔法与代码
【10月更文挑战第33天】本文将带你走进AI的世界,了解机器学习的原理和应用。我们将通过Python代码示例,展示如何实现一个简单的线性回归模型。无论你是AI新手还是有经验的开发者,这篇文章都会给你带来新的启示。让我们一起探索AI的奥秘吧!
|
6天前
|
机器学习/深度学习 人工智能 自然语言处理
探索AI的奥秘:机器学习入门指南
【10月更文挑战第30天】本篇文章是一份初学者友好的机器学习入门指南,旨在帮助读者理解并开始实践机器学习。我们将介绍机器学习的基本概念,包括监督学习、无监督学习和强化学习等。我们还将提供一些实用的代码示例,以帮助读者更好地理解和应用这些概念。无论你是编程新手,还是有一定经验的开发者,这篇文章都将为你提供一个清晰的机器学习入门路径。
23 2
|
28天前
|
数据采集 移动开发 数据可视化
模型预测笔记(一):数据清洗分析及可视化、模型搭建、模型训练和预测代码一体化和对应结果展示(可作为baseline)
这篇文章介绍了数据清洗、分析、可视化、模型搭建、训练和预测的全过程,包括缺失值处理、异常值处理、特征选择、数据归一化等关键步骤,并展示了模型融合技术。
43 1
模型预测笔记(一):数据清洗分析及可视化、模型搭建、模型训练和预测代码一体化和对应结果展示(可作为baseline)
|
14天前
|
机器学习/深度学习 数据采集 人工智能
揭秘AI的魔法:机器学习如何改变我们的世界
【10月更文挑战第22天】在这篇文章中,我们将深入探讨机器学习的奥秘,揭示它是如何在我们的日常生活中扮演着越来越重要的角色。从简单的数据分类到复杂的预测模型,机器学习的应用已经渗透到各个领域。我们将通过实例和代码示例,展示机器学习的基本概念、工作原理以及它如何改变我们的生活。无论你是科技爱好者还是对AI充满好奇的初学者,这篇文章都将为你打开一扇通往未来的大门。
|
24天前
|
机器学习/深度学习 存储 人工智能
揭秘机器学习背后的神秘力量:如何高效收集数据,让AI更懂你?
【10月更文挑战第12天】在数据驱动的时代,机器学习广泛应用,从智能推荐到自动驾驶。本文以电商平台个性化推荐系统为例,探讨数据收集方法,包括明确数据需求、选择数据来源、编写代码自动化收集、数据清洗与预处理及特征工程,最终完成数据的训练集和测试集划分,为模型训练奠定基础。
37 3
|
1月前
|
机器学习/深度学习 人工智能 安全
自动化测试的未来:AI与机器学习的结合
随着技术的发展,软件测试领域正迎来一场革命。自动化测试,一度被认为是提高效率和准确性的黄金标准,如今正在被人工智能(AI)和机器学习(ML)的浪潮所推动。本文将探讨AI和ML如何改变自动化测试的面貌,提供代码示例,并展望这一趋势如何塑造软件测试的未来。我们将从基础概念出发,逐步深入到实际应用,揭示这一技术融合如何为测试工程师带来新的挑战和机遇。
57 3
|
2月前
|
机器学习/深度学习 人工智能 自然语言处理
自动化测试的未来:AI与机器学习的融合
【9月更文挑战第29天】在软件测试领域,自动化测试一直是提高测试效率和质量的关键。随着人工智能(AI)和机器学习(ML)技术的飞速发展,它们正逐步渗透到自动化测试中,预示着一场测试革命的来临。本文将探讨AI和ML如何重塑自动化测试的未来,通过具体案例展示这些技术如何优化测试流程,提高测试覆盖率和准确性,以及它们对测试工程师角色的影响。
85 7
下一篇
无影云桌面