分子AI预测赛笔记

优雅的造轮狮 2024-07-29 11:01:02 阅读 95

#AI夏令营 #Datawhale #夏令营

Taks1 跑通baseline

根据task1跑通baseline

注册账号

直接注册或登录百度账号,etc

fork 项目

零基础入门 Ai 数据挖掘竞赛-速通 Baseline - 飞桨AI Studio星河社区

启动项目 

选择运行环境,并点击确定,没有特殊要求就默认的基础版就可以了

等待片刻,等待在线项目启动

运行项目代码

点击 运行全部Cell

程序运行完生成文件 submit.csv

这个文件就最终提交的文件。

 Taks2 赛题深入解析

理解赛题,了解机器学习竞赛通用流程

数据字段理解 

重点对 Smiles、Assay (DC50/Dmax)、Assay (Protac to Target, IC50)、Assay (Cellular activities, IC5、Article DOI、InChI字段学习分析

预测目标

选手需要预测PROTACs的降解能力,具体来说,就是预测<code>Label字段的值。

根据DC50Dmax的值来判断降解能力的好坏:如果DC50大于100nM且Dmax小于80%,则Label为0;如果DC50小于等于100nM或Dmax大于等于80%,则Label为1。

零基础入门AI(机器学习)竞赛 - 飞书云文档

https://datawhaler.feishu.cn/wiki/Ue7swBbiJiBhsdk5SupcqfL7nLXDocs

icon-default.png?t=N7T8

https://datawhaler.feishu.cn/wiki/Ue7swBbiJiBhsdk5SupcqfL7nLX

学习 https://www.bilibili.com/read/cv35897986/?jump_opus=

导入库 (task1)

导入了一些在数据科学和机器学习中常用的库,为后续的数据处理和模型训练做准备 

<code># 导入numpy库,用于进行科学计算 CSDN@优雅的造轮狮

import numpy as np

# 导入pandas库,用于数据分析和数据处理

import pandas as pd

# 导入CatBoostClassifier,CatBoost是一个梯度提升库,用于分类任务

from catboost import CatBoostClassifier

# 从sklearn.model_selection导入StratifiedKFold, KFold, GroupKFold

# StratifiedKFold: 分层K折交叉验证

# KFold: 简单的K折交叉验证

# GroupKFold: 对具有相同组的数据进行K折交叉验证

from sklearn.model_selection import StratifiedKFold, KFold, GroupKFold

# 从sklearn.metrics导入f1_score,用于计算F1分数,即精确率和召回率的调和平均数

from sklearn.metrics import f1_score

# 从rdkit导入Chem,RDKit是一个开源的化学信息学软件包,用于化学数据的处理和分析

from rdkit import Chem

# 从rdkit.Chem导入Descriptors,用于计算化学分子的描述符

from rdkit.Chem import Descriptors

# 从sklearn.feature_extraction.text导入TfidfVectorizer,用于文本数据的TF-IDF向量化

from sklearn.feature_extraction.text import TfidfVectorizer

# 导入tqdm库,用于在循环中显示进度条

import tqdm

# 导入sys库,提供对解释器使用或维护的接口

import sys

# 导入os库,提供了一种方便的方式来使用操作系统依赖的功能

import os

# 导入gc库,用于垃圾回收

import gc

# 导入re库,用于正则表达式操作

import re

# 导入argparse库,用于解析命令行参数

import argparse

# 导入warnings库,用于警告控制

import warnings

# 忽略警告信息

warnings.filterwarnings('ignore')

 导入数据 (task1)

# 使用pandas库中的read_excel()函数从指定的Excel文件中读取训练集数据 CSDN@优雅的造轮狮

# './data/data280993/traindata-new.xlsx'是文件的相对路径

# 读取的数据被存储在名为train的pandas DataFrame中

train = pd.read_excel('./data/data280993/traindata-new.xlsx')

# 使用read_excel()函数从指定的Excel文件中读取测试集数据

# './data/data280993/testdata-new.xlsx'是文件的相对路径

# 读取的数据被存储在名为test的pandas DataFrame中

test = pd.read_excel('./data/data280993/testdata-new.xlsx')

数据集通常用于机器学习模型的训练和测试。

训练集用于训练模型,而测试集用于评估模型的性能。

查看数据 (task2)

基本情况

# 调用train DataFrame的info()方法 CSDN@优雅的造轮狮

# info()方法会返回DataFrame的基本信息,包括:

# - 每列的名称和数据类型

# - DataFrame中非空值的数量

# - DataFrame的内存使用情况

data = train.info()

# 这些信息会被打印到控制台

data

info()函数是pandas库提供的一个方法,用于快速查看DataFrame的基本情况,包括每列的数据类型、非空值的数量、内存使用情况等。

# 使用describe()方法获取train DataFrame的描述性统计信息 CSDN@优雅的造轮狮

description = train.describe()

description

describe()方法来获取数据的描述性统计信息,包括计数、均值、标准差、最小值、四分位数和最大值。 

从打印的数据看,部分数据的数据项比较少。可以筛掉减少拟合

查看object类型的列表

# 使用select_dtypes()方法选择train DataFrame中数据类型为object的所有列 CSDN@优雅的造轮狮

# include参数设置为'object',意味着只选择数据类型为object的列

# columns属性返回这些列的名称

object_columns = train.select_dtypes(include='object').columnscode>

使用pandas库中的select_dtypes()方法来选择train DataFrame中数据类型为object的所有列。

object类型在pandas中通常用于存储字符串数据或者其他Python对象。 

缺失值查看

# 缺失值查看 CSDN@优雅的造轮狮

temp = train.isnull().sum()

temp[temp > 0]

 isnull()方法用于检测DataFrame中的缺失值,返回一个布尔DataFrame,其中True表示缺失值,sum()方法则对每一列的True值进行求和,从而得到每一列缺失值的数量。

# 使用isnull()方法检测train DataFrame中的缺失值 CSDN@优雅的造轮狮

# 返回一个布尔DataFrame,其中True表示缺失值

null_counts = train.isnull().sum()

# 使用布尔索引选择缺失值数量大于0的列

# 这将返回一个Series,其中包含有缺失值的列及其缺失值的数量

missing_values = null_counts[null_counts > 0]

唯一值个数判断 

# 获取train DataFrame的所有列名 CSDN@优雅的造轮狮

# columns属性返回一个包含所有列名的Index对象

fea = train.columns

# 将Index对象转换为列表

# tolist()方法将Index对象中的元素转换为Python列表

fea = fea.tolist()

fea

columns属性返回一个包含DataFrame所有列名的Index对象,而tolist()方法将这个Index对象转换为一个列表。

 输出唯一值

# 输出唯一值

for f in fea:

    print(f,train[f].nunique());# nunique() 统计列中的唯一值

没看出啥端倪(DOGE) 

数据预处理(task3)

# 从训练集中删除'DC50 (nM)'和'Dmax (%)'这两列 CSDN@优雅的造轮狮

# axis=1表示操作的是列

train = train.drop(['DC50 (nM)', 'Dmax (%)'], axis=1)

# 定义一个空列表drop_cols,用于存储在测试数据集中非空值小于10个的列名

drop_cols = []

for f in test.columns:

# 使用notnull().sum()计算每列非空值的数量

# 如果非空值的数量小于10,则将该列的名称添加到drop_cols列表中

if test[f].notnull().sum() < 10:

drop_cols.append(f)

# 使用drop方法从训练集和测试集中删除drop_cols列表中的列

# 这是为了避免在后续的分析或建模中使用这些包含大量缺失值的列

train = train.drop(drop_cols, axis=1)

test = test.drop(drop_cols, axis=1)

# 使用pd.concat将清洗后的训练集和测试集合并成一个名为data的DataFrame

# axis=0表示沿着行的方向合并,ignore_index=True表示忽略原始的索引,创建新的索引

data = pd.concat([train, test], axis=0, ignore_index=True)

# 获取data DataFrame中从第三列开始的所有列名

# 这可能是为了后续的特征工程或模型训练做准备

cols = data.columns[2:]

将SMILES转换为分子对象列表

# 将SMILES转换为分子对象列表,并转换为SMILES字符串列表

data['smiles_list'] = data['Smiles'].apply(lambda x:[Chem.MolToSmiles(mol, isomericSmiles=True) for mol in [Chem.MolFromSmiles(x)]])

data['smiles_list'] = data['smiles_list'].map(lambda x: ' '.join(x))

使用TfidfVectorizer计算TF-IDF

# 使用TfidfVectorizer计算TF-IDF CSDN@优雅的造轮狮

tfidf = TfidfVectorizer(max_df = 0.9, min_df = 1, sublinear_tf = True)

res = tfidf.fit_transform(data['smiles_list'])

转为dataframe格式并合并

# 将结果转为dataframe格式 CSDN@优雅的造轮狮

tfidf_df = pd.DataFrame(res.toarray())

tfidf_df.columns = [f'smiles_tfidf_{i}' for i in range(tfidf_df.shape[1])]

# 按列合并到data数据

data = pd.concat([data, tfidf_df], axis=1)

自然数编码

# 自然数编码 CSDN@优雅的造轮狮

def label_encode(series):

unique = list(series.unique())

return series.map(dict(zip(

unique, range(series.nunique())

)))

# 对每个类转换为其编码

for col in cols:

if data[col].dtype == 'object':

data[col] = label_encode(data[col])

 对InChI进行展开构建特征 (Task4)

对 InChI 进行展开构建特征是一种将化学物质的结构信息转化为数值特征的方法。通过展开 InChI,并根据展开后的结构信息提取特征,可以用于化学物质的分类、相似性计算、性质预测等任务。展开 InChI 可以将化学物质的结构信息转化为原子、键、环等级别的信息,然后可以利用这些信息来构建特征

atomic_masses = {

'H': 1.008, 'He': 4.002602, 'Li': 6.94, 'Be': 9.0122, 'B': 10.81, 'C': 12.01,

'N': 14.01, 'O': 16.00, 'F': 19.00, 'Ne': 20.180, 'Na': 22.990, 'Mg': 24.305,

'Al': 26.982, 'Si': 28.085, 'P': 30.97, 'S': 32.07, 'Cl': 35.45, 'Ar': 39.95,

'K': 39.10, 'Ca': 40.08, 'Sc': 44.956, 'Ti': 47.867, 'V': 50.942, 'Cr': 52.00,

'Mn': 54.938, 'Fe': 55.845, 'Co': 58.933, 'Ni': 58.69, 'Cu': 63.55, 'Zn': 65.38

}

# 函数用于解析单个InChI字符串

def parse_inchi(row):

inchi_str = row['InChI']

formula = ''

molecular_weight = 0

element_counts = {}

# 提取分子式

formula_match = re.search(r"InChI=1S/([^/]+)/c", inchi_str)

if formula_match:

formula = formula_match.group(1)

# 计算分子量和原子计数

for element, count in re.findall(r"([A-Z][a-z]*)([0-9]*)", formula):

count = int(count) if count else 1

element_mass = atomic_masses.get(element.upper(), 0)

molecular_weight += element_mass * count

element_counts[element.upper()] = count

return pd.Series({

'Formula': formula,

'MolecularWeight': molecular_weight,

'ElementCounts': element_counts

})

# 应用函数到DataFrame的每一行

train[['Formula', 'MolecularWeight', 'ElementCounts']] = train.apply(parse_inchi, axis=1)

# 定义存在的key

keys = ['H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al', 'Si', 'P', 'S', 'Cl', 'Ar', 'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu', 'Zn']

# 创建一个空的DataFrame,列名为keys

df_expanded = pd.DataFrame({key: pd.Series() for key in keys})

# 遍历数据,填充DataFrame

for index, item in enumerate(train['ElementCounts'].values):

for key in keys:

# 将字典中的值填充到相应的列中

df_expanded.at[index, key] = item.get(key, 0)

df_expanded = pd.DataFrame(df_expanded)

# 按列合并到data数据

data = pd.concat([data, df_expanded], axis=1)

构建训练集和测试集 

# 提取data中label行不为空的,将其作为train的数据并更新索引 CSDN@优雅的造轮狮

train = data[data.Label.notnull()].reset_index(drop=True)

# 提取data中label行为空的,将其作为teat的数据并更新索引

test = data[data.Label.isnull()].reset_index(drop=True)

# 特征筛选

features = [f for f in train.columns if f not in ['uuid','Label','smiles_list']]

# 构建训练集和测试集

x_train = train[features]

x_test = test[features]

# 训练集标签

y_train = train['Label'].astype(int)

使用采用5折交叉验证

def cv_model(clf, train_x, train_y, test_x, clf_name, seed=2022):

# 进行5折交叉验证

kf = KFold(n_splits=5, shuffle=True, random_state=seed)

train = np.zeros(train_x.shape[0])

test = 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), str(seed)))

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]

# 配置CatBoost分类器的参数

params = {'learning_rate': 0.05, 'depth': 8, 'l2_leaf_reg': 10, 'bootstrap_type':'Bernoulli','random_seed':seed,

'od_type': 'Iter', 'od_wait': 100, 'random_seed': 11, 'allow_writing_files': False, 'task_type':'CPU'}

# 使用CatBoost分类器训练模型

model = clf(iterations=20000, **params, eval_metric='AUC')code>

model.fit(trn_x, trn_y, eval_set=(val_x, val_y),

metric_period=100,

cat_features=[],

use_best_model=True,

verbose=1)

val_pred = model.predict_proba(val_x)[:,1]

test_pred = model.predict_proba(test_x)[:,1]

train[valid_index] = val_pred

test += test_pred / kf.n_splits

cv_scores.append(f1_score(val_y, np.where(val_pred>0.5, 1, 0)))

print(cv_scores)

print("%s_score_list:" % clf_name, cv_scores)

print("%s_score_mean:" % clf_name, np.mean(cv_scores))

print("%s_score_std:" % clf_name, np.std(cv_scores))

return train, test

cat_train, cat_test = cv_model(CatBoostClassifier, x_train, y_train, x_test, "cat")

这段代码是一个交叉验证模型的函数,用于训练和评估分类器模型。用了CatBoost分类器,在给定的训练数据集上进行了5折交叉验证,并返回了训练集和测试集的预测结果。

函数中的参数包括:

clf: 分类器模型的类对象,这里是CatBoostClassifier。train_x, train_y: 训练数据的特征和标签。test_x: 测试数据的特征。clf_name: 分类器的名称,用于输出结果。seed: 随机种子,默认为2022。

函数的主要流程如下:

创建了一个5折交叉验证器(KFold)。初始化了训练集和测试集的预测结果数组。在每一折循环中,根据训练索引和验证索引分割训练集和验证集。配置CatBoost分类器的参数,并使用训练集训练模型。对验证集和测试集进行预测,并将预测结果加入到结果数组中。计算并保存每一折验证集的F1分数。输出每一折的F1分数列表、平均分数和标准差。返回训练集和测试集的预测结果。

输出结果

from datetime import datetime CSDN@优雅的造轮狮

current_time = datetime.now() # 获取当前时间

formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S") # 格式化时间

# print("当前时间:", current_time)

# print("格式化时间:", formatted_time)

# 5. 保存结果文件到本地

pd.DataFrame(

{

'uuid': test['uuid'],

'Label': pred

}

).to_csv(formatted_time+ '.csv', index=None)

【每日竞答】7.4

Q1: 大家知道我们的Baseline是基于决策树的,那么大家知道决策树经典的属性划分方法有哪些?决策树在实际应用中有哪些优缺点?简单介绍即可。

A: 

(1)基于信息增益判断:基于熵的概念,选择能够最大程度减少数据集熵的属性进行划分。常用于ID3算法; 基于信息增益率判断:对信息增益进行改进,考虑到属性取值较多的问题,选择信息增益率最高的属性进行划分。常用于C4.5算法;基于基尼指数判断: 选择基尼指数最小的属性进行划分。基尼指数衡量的是数据集的纯度。常用于CART(分类与回归树)算法。

(2)优点:计算复杂度不高,便于使用,高效,能够处理多种数据类型,可很容易地构造出易于理解的规则。

缺点:易过拟合,对噪声数据敏感,忽略数据集中属性之间的相关性,不稳定等。

Q2: 在机器学习中,过拟合现象是非常常见的。大家知道什么是过拟合吗?如何防止过拟合?请简单说明。

A: 

(1)过拟合是指模型过于紧密或精确地匹配特定数据集,泛化能力差,导致在新的、未见过的数据上表现不佳。

(2)防止过拟合的方法有很多。例如:数据增强:通过对训练数据进行变换,比如旋转、缩放、翻转等,增加数据的多样性,帮助模型学习到更一般的特征。正则化:添加正则项到损失函数中可以惩罚模型的复杂度,限制模型权重的大小,从而减少过拟合。提前停止:在机器学习模型学习数据中的噪音之前,提前停止暂停训练阶段。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。