分子AI预测赛笔记

#AI夏令营 #Datawhale #夏令营

Taks1 跑通baseline

根据task1跑通baseline

注册账号

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

fork 项目

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

启动项目 

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

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

运行项目代码

点击 运行全部Cell

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

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

 Taks2 赛题深入解析

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

数据字段理解 

Docs

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

预测目标

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

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

零基础入门AI(机器学习)竞赛 - 飞书云文档
https://datawhaler.feishu.cn/wiki/Ue7swBbiJiBhsdk5SupcqfL7nLXDocsicon-default.png?t=N7T8https://datawhaler.feishu.cn/wiki/Ue7swBbiJiBhsdk5SupcqfL7nLXTask3初步调试参数

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

导入库 (task1)

# 导入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').columns

使用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() 统计列中的唯一值

数据预处理(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)

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')

        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。

函数的主要流程如下:

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

通过调用这个函数,可以得到CatBoost分类器在给定数据集上的交叉验证结果,评估模型的性能以及获取训练集和测试集的预测结果。

输出结果

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)

这个夏令营不简单 #AI夏令营 #Datawhale #夏令营 

【每日竞答】7.4

Q1: 大家知道我们的Baseline是基于决策树的,那么大家知道决策树经典的属性划分方法有哪些?决策树在实际应用中有哪些优缺点?简单介绍即可。
A: 
(1)基于信息增益判断:基于熵的概念,选择能够最大程度减少数据集熵的属性进行划分。常用于ID3算法; 基于信息增益率判断:对信息增益进行改进,考虑到属性取值较多的问题,选择信息增益率最高的属性进行划分。常用于C4.5算法;基于基尼指数判断: 选择基尼指数最小的属性进行划分。基尼指数衡量的是数据集的纯度。常用于CART(分类与回归树)算法。
(2)优点:计算复杂度不高,便于使用,高效,能够处理多种数据类型,可很容易地构造出易于理解的规则。
缺点:易过拟合,对噪声数据敏感,忽略数据集中属性之间的相关性,不稳定等。

Q2: 在机器学习中,过拟合现象是非常常见的。大家知道什么是过拟合吗?如何防止过拟合?请简单说明。
A: 
(1)过拟合是指模型过于紧密或精确地匹配特定数据集,泛化能力差,导致在新的、未见过的数据上表现不佳。
(2)防止过拟合的方法有很多。例如:数据增强:通过对训练数据进行变换,比如旋转、缩放、翻转等,增加数据的多样性,帮助模型学习到更一般的特征。正则化:添加正则项到损失函数中可以惩罚模型的复杂度,限制模型权重的大小,从而减少过拟合。提前停止:在机器学习模型学习数据中的噪音之前,提前停止暂停训练阶段。

  • 22
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值