import numpy as np import pandas as pd from catboost import CatBoostClassifier from sklearn.model_selection import StratifiedKFold, KFold, GroupKFold from sklearn.metrics import f1_score from rdkit import Chem from rdkit.Chem import Descriptors from sklearn.feature_extraction.text import TfidfVectorizer import tqdm, sys, os, gc, re, argparse, warnings
numpy
(np
): 一个用于科学计算的库,提供多维数组对象、派生对象(如掩码数组和矩阵)以及用于快速操作数组的各种例程,如数学、逻辑、形状操作、排序、选择等。
pandas
(pd
): 提供高性能、易用的数据结构和数据分析工具,适用于处理表格数据(例如CSV文件、SQL查询结果等)。
catboost
: 由Yandex开发的一个机器学习库,提供对称树算法的实现,用于分类、回归和其他机器学习任务。
sklearn
: 即scikit-learn,是Python中一个广泛使用的机器学习库,提供简单有效的工具用于数据挖掘和数据分析,包括模型选择、数据分割、预处理、元学习等。
StratifiedKFold
, KFold
, GroupKFold
: 这些是sklearn
中的交叉验证类,用于模型评估时的数据分割,以确保训练集和测试集的分布一致性。
f1_score
: F1分数是sklearn.metrics
模块中的一个指标,用于评估二分类模型的性能,它是精确率和召回率的调和平均值。
rdkit
: 一个开源化学信息学软件库,用于处理化学分子、反应和相关数据。
Descriptors
: rdkit
中的一个模块,用于计算化学分子的各种描述符。
TfidfVectorizer
: 来自sklearn.feature_extraction.text
,用于将文本数据转换为TF-IDF特征。
tqdm
: 一个快速、可扩展的Python进度条库,可以在长循环中添加一个进度提示信息,用户只需要封装任意的迭代器 tqdm(iterator)
。
sys
: 提供了与Python解释器密切相关的函数和变量。
os
: 一个Python标准库,用于使用操作系统依赖的功能。
gc
: 控制垃圾收集器的接口,用于管理内存。
re
: 一个提供正则表达式匹配操作的库。
argparse
: 编写用户友好的命令行接口的库。
warnings
: 一个用于发出警告信息的库。
warnings.filterwarnings('ignore') train = pd.read_excel("C:/Users/姜荣国/Downloads/traindata-new.xlsx") test = pd.read_excel("C:/Users/姜荣国/Downloads/testdata-new.xlsx") # test数据不包含 DC50 (nM) 和 Dmax (%) train = train.drop(['DC50 (nM)', 'Dmax (%)'], axis=1) # 定义了一个空列表drop_cols,用于存储在测试数据集中非空值小于10个的列名。 drop_cols = [] for f in test.columns: if test[f].notnull().sum() < 10: drop_cols.append(f) # 使用drop方法从训练集和测试集中删除了这些列,以避免在后续的分析或建模中使用这些包含大量缺失值的列 train = train.drop(drop_cols, axis=1) test = test.drop(drop_cols, axis=1) # 使用pd.concat将清洗后的训练集和测试集合并成一个名为data的DataFrame,便于进行统一的特征工程处理 data = pd.concat([train, test], axis=0, ignore_index=True) cols = data.columns[2:] # 将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 tfidf = TfidfVectorizer(max_df=0.9, min_df=1, sublinear_tf=True) res = tfidf.fit_transform(data['smiles_list']) # 将结果转为dataframe格式 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)
-
忽略警告:使用
warnings.filterwarnings('ignore')
来忽略可能产生的警告信息,以避免控制台输出不必要的警告。 -
读取数据:使用
pandas
的read_excel
函数从指定的路径读取训练集和测试集数据。 -
数据清洗:
- 从训练集中删除了两列
'DC50 (nM)'
和'Dmax (%)'
,因为测试数据不包含这两列。 - 遍历测试集的列,找出非空值少于10个的列,并存储在
drop_cols
列表中。 - 从训练集和测试集中删除这些含有大量缺失值的列。
- 从训练集中删除了两列
-
合并数据集:使用
pd.concat
将清洗后的训练集和测试集合并成一个 DataFramedata
,便于进行统一的特征工程处理。 -
特征工程:
- 对
'Smiles'
列中的每个 SMILES 字符串进行处理,转换为分子对象,然后再次转换回 SMILES 字符串格式,并存储在新的'smiles_list'
列中。 - 使用
TfidfVectorizer
计算'smiles_list'
列的 TF-IDF 特征。
- 对
-
TF-IDF 特征向量化:
- 使用
fit_transform
方法计算 TF-IDF 特征矩阵。 - 将 TF-IDF 矩阵转换为 DataFrame
tfidf_df
。 - 将 TF-IDF 特征按列合并回原始的 DataFrame
data。
- 使用
# 自然数编码 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]) train = data[data.Label.notnull()].reset_index(drop=True) 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)
-
自然数编码函数:定义了一个名为
label_encode
的函数,它接受一个 pandas Series 作为输入,并返回一个将分类值映射到自然数的 Series。这是处理分类特征的一种方法,特别是当这些特征需要用作模型输入时。 -
应用自然数编码:遍历 DataFrame
data
中的列,对于数据类型为'object'
(通常指字符串)的列,使用label_encode
函数进行编码。 -
分割训练集和测试集:基于
'Label'
列的存在与否,将合并后的 DataFrame 分割为训练集和测试集。data.Label.notnull()
创建一个布尔索引,用于选择非空标签的行作为训练集,而data.Label.isnull()
用于选择空标签的行作为测试集。 -
重置索引:使用
reset_index(drop=True)
重置训练集和测试集的索引,以便它们从0开始,并且原来的索引不再保留。 -
特征筛选:创建一个列表
features
,包含训练集中除了'uuid'
、'Label'
和'smile_list'
之外的所有列名。这些被排除的列可能是ID列或标签列,不应该作为特征输入到模型中。 -
构建特征矩阵:从训练集和测试集中选取
features
列表中的特征列,构建特征矩阵x_train
和x_test
。 -
提取标签:从训练集中提取标签列
'Label'
,将其转换为整数类型int
,以便用于模型训练。
def cv_model(clf, train_x, train_y, test_x, clf_name, seed=2022): 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 = [] # 100, 1 2 3 4 5 # 1 2 3 4 5 # 1 2 3 5。 4 # 1 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] params = {'learning_rate': 0.1, 'depth': 6, 'l2_leaf_reg': 10, 'bootstrap_type': 'Bernoulli', 'random_seed': seed, 'od_type': 'Iter', 'od_wait': 100, 'allow_writing_files': False, 'task_type': 'CPU'} 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") pd.DataFrame( { 'uuid': test['uuid'], 'Label': np.where(cat_test > 0.5, 1, 0) } ).to_csv('submit.csv', index=None)
-
交叉验证模型函数
cv_model
:- 接受分类器
clf
、训练集特征和标签train_x
,train_y
、测试集特征test_x
、分类器名称clf_name
和随机种子seed
作为参数。 - 使用
KFold
进行5折交叉验证,shuffle=True
表示在分折前打乱数据。
- 接受分类器
-
初始化:
train
和test
数组用于存储交叉验证中每个折的训练预测和测试集的预测。cv_scores
列表用于存储每一折的F1分数。
-
交叉验证循环:
- 遍历由
kf.split
生成的训练集索引和验证集索引。 - 打印当前折数和随机种子。
- 根据索引分割训练集和验证集数据。
- 设置CatBoost分类器的参数
params
。 - 训练CatBoost模型,并使用验证集评估模型性能。
- 使用验证集预测结果更新
train
数组,使用测试集的预测结果更新test
数组。 - 计算并存储当前折的F1分数。
- 遍历由
-
输出结果:
- 打印所有折的F1分数、平均值和标准差。
-
返回值:
- 返回交叉验证中的训练集预测结果
train
和测试集的预测结果test
。
- 返回交叉验证中的训练集预测结果
-
调用
cv_model
函数:- 使用
CatBoostClassifier
、训练集特征和标签x_train
,y_train
、测试集特征x_test
调用cv_model
函数。 - 将分类器名称设置为
"cat"
。
- 使用
-
生成提交文件:
- 使用测试集的
uuid
和cat_test
中的预测结果创建一个DataFrame。 - 将预测结果(通过阈值0.5判定)设置为 'Label' 列。
- 将这个DataFrame保存为CSV文件
submit.csv
,不包含索引。
- 使用测试集的