1 数据预处理(即数据清理)
train = pd.read_excel('./dataset-new/traindata-new.xlsx')
test = pd.read_excel('./dataset-new/testdata-new.xlsx')
1.1 删除无用的数据 drop
# test数据不包含 DC50 (nM) 和 Dmax (%)
train = train.drop(['DC50 (nM)', 'Dmax (%)'], axis=1)
1.2 删除缺失值大的数据 drop
# 定义了一个空列表drop_cols,用于存储在测试数据集中非空值小于10个的列名。
drop_cols = []
for f in test.columns:
if test[f].notnull().sum() < 10:
drop_cols.append(f)
1.3 删除包含大量缺失值的列 drop
# 使用drop方法从训练集和测试集中删除了这些列,以避免在后续的分析或建模中使用
这些包含大量缺失值的列
train = train.drop(drop_cols, axis=1)
test = test.drop(drop_cols, axis=1)
1.4 方便统一的特征工程处理
最后,使用pd.concat将清洗后的训练集和测试集合并成一个名为data的DataFrame,便于进行统一的特征工程处理
data = pd.concat([train, test], axis=0, ignore_index=True)
cols = data.columns[2:]
2 特征工程
2.1 SMILES转化
使用 RDKit 库将数据集中的SMILES字符串转换回SMILES字符串的列表。这里看起来有些冗余,因为您已经拥有SMILES字符串,但可能您想确保所有SMILES都是以相同的方式(例如,考虑异构体信息)处理的。
# 将SMILES转换为分子对象列表,并转换为SMILES字符串列表
data['smiles_list'] = data['Smiles'].apply(lambda x:[Chem.MolToSmiles(mol,
isomericSmiles=True) for mol in [Chem.MolFromSmiles(x)]])
2.2 字符串处理
将SMILES字符串列表转换为单个字符串,每个SMILES之间用空格分隔。
data['smiles_list'] = data['smiles_list'].map(lambda x: ' '.join(x))
2.3 TF-IDF计算
使用 TfidfVectorizer 从处理后的SMILES字符串创建 TF-IDF特征矩阵。
# 使用TfidfVectorizer计算TF-IDF
tfidf = TfidfVectorizer(max_df = 0.9, min_df = 1, sublinear_tf = True)
res = tfidf.fit_transform(data['smiles_list'])
2.4 转换为DataFrame
将TF-IDF矩阵转换为DataFrame,以便与原始数据集结合。
# 将结果转为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)
2.5 自然数编码
定义了一个函数 label_encode ,用于将分类特征(对象类型)转换为整数编码。
# 自然数编码
def label_encode(series):
unique = list(series.unique())
return series.map(dict(zip(
unique, range(series.nunique())
)))
2.6 特征和标签准备
- 对于所有的特征列(cols),如果它们的数据类型是对象(通常表示为字符串),则应用自然数编码。
- 从合并后的数据集中分离出训练集和测试集,其中训练集包含标签(Label),测试集不包含。
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)
2.7 特征筛选
从训练集和测试集中筛选出特征列(不包括 uuid 、Label 和 smiles_list ),并从训练集中提取标签列。
# 特征筛选
features = [f for f in train.columns if f not in ['uuid','Label','smiles_list']]
2.8 数据类型转换
将标签列 Label 转换为整数类型,以便于模型训练。
# 构建训练集和测试集
x_train = train[features]
x_test = test[features]
# 训练集标签
y_train = train['Label'].astype(int)
3 模型训练与预测
代码定义了一个名为 cv_model 的函数,用于使用交叉验证训练分类模型,并对测试集进行预测。以下是代码的详细步骤和说明:
3.1 函数定义
cv_model 函数接受分类器对象 clf ,训练特征集 train_x 和标签集 train_y,测试特征集 text_x,分类器名称 clf_name,以及可选的随机种子 seed。
def cv_model(clf, train_x, train_y, test_x, clf_name, seed=2022):
3.2 交叉验证设置
使用 kFold 进行 5折交叉验证, shuffle=True 表示在分折前打乱数据。
kf = KFold(n_splits=5, shuffle=True, random_state=seed)
3.3 初始化变量
创建两个数组 train 和 text 来存储交叉验证过程中的训练集预测和测试集预测。
train = np.zeros(train_x.shape[0])
test = np.zeros(test_x.shape[0])
3.4 循环执行交叉验证
- 对每一折数据,使用训练索引 train_index 和验证索引 vaild_index 分割训练集和验证集。
- 打印当前折数和随机种子。
- 设置 CatBoost 分类器的参数 params 。
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'}
3.5 模型训练
使用 CatBoost 分类器训练模型,iterations=20000 表示最大迭代次数,eval_metric='AUC' 表示使用 AUC 作为评估指标。
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)
3.6 模型评估
- 使用验证集 val_x 和 val_y 对模型进行评估,获取预测概率 val_pred 。
- 使用测试集 test_x 获取测试集预测概率 test_pred 。
val_pred = model.predict_proba(val_x)[:,1]
test_pred = model.predict_proba(test_x)[:,1]
3.7 保存结果
将验证集的预测结果存储在 train 数组中,将测试集的预测结果累加到 test 数组中,并计算当前折的 F1 分数。
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)))
3.8 输出和返回结果
- 打印所有折的 F1 分数、平均值和标准差。
- 返回训练集预测结果 train 和测试集预测结果 test 。
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
3.9 模型应用
- 使用 cv_model 函数训练 CatBoost 分类器,并将返回的测试集预测结果 cat_test 用于生成提交文件。
- 根据预测概率 cat_test 生成二元标签,概率大于0.5的预测为1,否则为0。
cat_train, cat_test = cv_model(CatBoostClassifier, x_train, y_train, x_test, "cat")
3.10 生成提交文件
创建一个包含 uuid 和预测标签 Label 的 DataFrame,并将其保存为 CSV 文件。
pd.DataFrame(
{
'uuid': test['uuid'],
'Label': np.where(cat_test>0.5, 1, 0)
}
).to_csv('submit.csv', index=None)
4 附加学习列表
- TEIDF学习:TF-IDF(Term Frequency-Inverse Document Frequency)是一种用于信息检索与文本挖掘的常用加权技术。它是一种统计方法,用以评估一个词语对于一个文件集或一个语料库中的其中一份文件的重要程度。它的主要思想是:如果某个词语在一篇文章中出现的频率高(Term Frequency,TF),并且在其他文章中很少出现(Inverse Document Frequency,IDF),则认为这个词语具有很好的类别区分能力,对这篇文章的内容有很好的指示作用。
- 交叉验证学习:交叉验证(Cross-Validation)是一种统计方法,用于评估并提高模型的预测性能,特别是在样本数量有限的情况下。它可以帮助我们评估模型的泛化能力,即在未知数据上的表现能力,从而减少模型过拟合的风险。
- CatBoost:CatBoost是一个开源的梯度提升库,由俄罗斯的搜索引擎公司Yandex开发。它专为处理分类和回归任务而设计,尤其擅长处理具有大量类别特征(categorical features)的数据集。CatBoost的名称来源于“Categorical Boosting”,即对类别特征进行增强的算法。