Datawhale AI 夏令营 第二届世界科学智能大赛 生命科学赛道:siRNA药物药效预测 Task2:深入理解赛题,入门RNN和特征工程中对“基于lightgbm的baseline”的优化分析

Task2中对“基于lightgbm的baseline”的优化分析

提示:此处仅有作者对标题内容的简析



前言

在阅读“Task2:深入理解赛题,入门RNN和特征工程”文档后,平台给出了数据的特征工程的分析方法,并根据序列模式提取特征。在得到了表格数据之后,平台使用了适用于表格数据的机器学习回归模型lightgbm模型来进行预测。本文章在此方法基础上给出分析和优化。


提示:以下是本篇文章正文内容

基于lightgbm的baseline

示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

1.数据加载和预处理

代码如下:

df_original = pd.read_csv("train_data.csv")
n_original = df_original.shape[0]
df_submit = pd.read_csv("sample_submission.csv")
df = pd.concat([df_original, df_submit], axis=0).reset_index(drop=True)

其中,
df将训练数据和提交样本数据合并,为后续的特征工程和模型训练提供完整的数据集。

2.特征工程

代码如下:

def siRNA_feat_builder(s: pd.Series, anti: bool = False):
    name = "anti" if anti else "sense"
    df = s.to_frame()
    # 序列长度
    df[f"feat_siRNA_{name}_seq_len"] = s.str.len()
    for pos in [0, -1]:
        for c in list("AUGC"):
            # 第一个和最后一个是否是A/U/G/C
            df[f"feat_siRNA_{name}_seq_{c}_{'front' if pos == 0 else 'back'}"] = (
                s.str[pos] == c
            )
    # 是否已某一对碱基开头和某一对碱基结尾
    df[f"feat_siRNA_{name}_seq_pattern_1"] = s.str.startswith("AA") & s.str.endswith(
        "UU"
    )
    df[f"feat_siRNA_{name}_seq_pattern_2"] = s.str.startswith("GA") & s.str.endswith(
        "UU"
    )
    df[f"feat_siRNA_{name}_seq_pattern_3"] = s.str.startswith("CA") & s.str.endswith(
        "UU"
    )
    df[f"feat_siRNA_{name}_seq_pattern_4"] = s.str.startswith("UA") & s.str.endswith(
        "UU"
    )
    df[f"feat_siRNA_{name}_seq_pattern_5"] = s.str.startswith("UU") & s.str.endswith(
        "AA"
    )
    df[f"feat_siRNA_{name}_seq_pattern_6"] = s.str.startswith("UU") & s.str.endswith(
        "GA"
    )
    df[f"feat_siRNA_{name}_seq_pattern_7"] = s.str.startswith("UU") & s.str.endswith(
        "CA"
    )
    df[f"feat_siRNA_{name}_seq_pattern_8"] = s.str.startswith("UU") & s.str.endswith(
        "UA"
    )
    # 第二位和倒数第二位是否为A
    df[f"feat_siRNA_{name}_seq_pattern_9"] = s.str[1] == "A"
    df[f"feat_siRNA_{name}_seq_pattern_10"] = s.str[-2] == "A"
    # GC占整体长度的比例
    df[f"feat_siRNA_{name}_seq_pattern_GC_frac"] = (
        s.str.contains("G") + s.str.contains("C")
    ) / s.str.len()
    return df.iloc[:, 1:]

其中,
siRNA_feat_builder函数对siRNA序列进行特征构造,生成多个新特征:
feat_siRNA_{name}seq_len:序列长度。
feat_siRNA
{name}seq{c}{‘front’ if pos == 0 else ‘back’}:序列首尾位置是否为特定碱基。
feat_siRNA
{name}seq_pattern*:序列特定模式匹配。
feat_siRNA_{name}_seq_pattern_GC_frac:序列中G和C碱基的比例。

3.类别型变量处理

代码如下:

df_publication_id = pd.get_dummies(df.publication_id)
df_publication_id.columns = [
    f"feat_publication_id_{c}" for c in df_publication_id.columns
]
df_gene_target_symbol_name = pd.get_dummies(df.gene_target_symbol_name)
df_gene_target_symbol_name.columns = [
    f"feat_gene_target_symbol_name_{c}" for c in df_gene_target_symbol_name.columns
]
df_gene_target_ncbi_id = pd.get_dummies(df.gene_target_ncbi_id)
df_gene_target_ncbi_id.columns = [
    f"feat_gene_target_ncbi_id_{c}" for c in df_gene_target_ncbi_id.columns
]
df_gene_target_species = pd.get_dummies(df.gene_target_species)
df_gene_target_species.columns = [
    f"feat_gene_target_species_{c}" for c in df_gene_target_species.columns
]
df_siRNA_duplex_id = pd.get_dummies(df.siRNA_duplex_id)
df_siRNA_duplex_id.columns = [
    f"feat_siRNA_duplex_id_{c}" for c in df_siRNA_duplex_id.columns
]
df_cell_line_donor = pd.get_dummies(df.cell_line_donor)
df_cell_line_donor.columns = [
    f"feat_cell_line_donor_{c}" for c in df_cell_line_donor.columns
]
df_cell_line_donor["feat_cell_line_donor_hepatocytes"] = (
    (df.cell_line_donor.str.contains("Hepatocytes")).fillna(False).astype("int")
)
df_cell_line_donor["feat_cell_line_donor_cells"] = (
    df.cell_line_donor.str.contains("Cells").fillna(False).astype("int")
)

其中,
使用pd.get_dummies对多个类别型变量进行独热编码。

生成的新特征列名以feat_开头,后接原变量名和类别值。

通过字符串匹配,提取特定词汇,并生成对应的二进制特征。

4.数值型变量处理

代码如下:

df_siRNA_concentration = df.siRNA_concentration.to_frame()
df_Transfection_method = pd.get_dummies(df.Transfection_method)
df_Transfection_method.columns = [
    f"feat_Transfection_method_{c}" for c in df_Transfection_method.columns
]
df_Duration_after_transfection_h = pd.get_dummies(df.Duration_after_transfection_h)
df_Duration_after_transfection_h.columns = [
    f"feat_Duration_after_transfection_h_{c}"
    for c in df_Duration_after_transfection_h.columns
]

其中,
对siRNA浓度变量进行处理,将其转化为DataFrame格式。

对转染方法和转染持续时间变量进行独热编码,生成新的特征列。

5.特征合并

代码如下:

feats = pd.concat(
    [
        df_publication_id,
        df_gene_target_symbol_name,
        df_gene_target_ncbi_id,
        df_gene_target_species,
        df_siRNA_duplex_id,
        df_cell_line_donor,
        df_siRNA_concentration,
        df_Transfection_method,
        df_Duration_after_transfection_h,
        siRNA_feat_builder(df.siRNA_sense_seq, False),
        siRNA_feat_builder(df.siRNA_antisense_seq, True),
        df.iloc[:, -1].to_frame(),
    ],
    axis=1,
)

其中,
将所有生成的新特征进行合并,构成最终的特征集feats。
包括独热编码后的类别特征、数值特征和通过siRNA_feat_builder函数构建的序列特征。

5.数据划分与转换格式

代码如下:

X_train, X_test, y_train, y_test = train_test_split(
    feats.iloc[:n_original, :-1],
    feats.iloc[:n_original, -1],
    test_size=0.2,
    random_state=42,
)

train_data = lgb.Dataset(X_train, label=y_train)
test_data = lgb.Dataset(X_test, label=y_test, reference=train_data)

其中,
在划分完训练集和测试集后,将训练集和测试集转换为LightGBM的Dataset格式,方便模型训练和评估。

6.定义模型参数和训练

代码如下:

# 定义一个回调函数来打印验证集的结果
def print_validation_result(env):
    result = env.evaluation_result_list[-1]
    print(f"[{env.iteration}] {result[1]}'s {result[0]}: {result[2]}")

params = {
    "boosting_type": "gbdt",
    "objective": "regression",
    "metric": "root_mean_squared_error",
    "max_depth": 7,
    "learning_rate": 0.02,
    "verbose": 0,
}

gbm = lgb.train(
    params,
    train_data,
    num_boost_round=15000,
    valid_sets=[test_data],
    callbacks=[print_validation_result],
)

其中,
定义LightGBM模型的参数,包括提升类型、目标任务、评估指标、树的最大深度和学习率。

定义回调函数print_validation_result,用于打印每次迭代后的验证结果。

使用lgb.train进行模型训练,设置提升迭代次数为15000,并提供验证集和回调函数。

7.优化方向

在阅读Task2后,选定了几个优化方向:

特征工程角度来说,增加更多有意义的特征,如序列的理化性质、结构特征等等等。

模型角度来说,用不同的模型做对比实验,也集成多种模型的预测结果。同时,用网格搜索进行超参数调优来一步提升模型性能。

特别是在阅读Task1的优秀博客:https://hqusends.feishu.cn/docx/D10Ld9jzgoMWYkxROnkcMbGWnGd,其中提到“将 LightGBMLarge、CatBoost、NeuralNetFastAI、XGBoost、RandomForestMSE按照特定权重加权后效果也很好。这方面有人专门分析过,应该是自动搜参总结出来的。”后,我便一直在测试多模型的最优加权权重,目前还在调试和优化中,应该会在后续的笔记汇报结果。而已跑通且达到最优效果的的就是下面暂时完成的lightgbm超参数调优代码。

8.超参数调优

代码如下:

# 定义一个回调函数来打印验证集的结果
class CustomLoggerCallback:
    def __init__(self, period=1):
        self.period = period
    
    def __call__(self, env):
        if env.iteration % self.period == 0:
            result = env.evaluation_result_list[-1]
            print(f"[{env.iteration}] {result[1]}'s {result[0]}: {result[2]}")

# 定义Optuna优化的目标函数
def objective(trial):
    # 定义LightGBM的超参数空间
    param = {
        "objective": "regression",  # 回归
        "metric": "mae",  # 评估指标:平均绝对误差
        "verbosity": -1,  # 不输出训练信息
        "boosting_type": "gbdt",  # 梯度提升树
        "lambda_l1": trial.suggest_float("lambda_l1", 1e-8, 10.0, log=True),  # L1正则化
        "lambda_l2": trial.suggest_float("lambda_l2", 1e-8, 10.0, log=True),  # L2正则化
        "num_leaves": trial.suggest_int("num_leaves", 20, 300),  # 叶子节点数
        "feature_fraction": trial.suggest_float("feature_fraction", 0.4, 1.0),  # 特征采样比例
        "bagging_fraction": trial.suggest_float("bagging_fraction", 0.4, 1.0),  # 数据采样比例
        "bagging_freq": trial.suggest_int("bagging_freq", 1, 7),  # 采样频率
        "min_child_samples": trial.suggest_int("min_child_samples", 5, 100),  # 最小样本数
        "feature_pre_filter": False  # 不预先过滤特征
    }

    # 训练LightGBM模型
    gbm = lgb.train(
        param, 
        train_data,  
        valid_sets=[test_data],  
        num_boost_round=1000,  
        callbacks=[lgb.early_stopping(stopping_rounds=50), CustomLoggerCallback(period=100)]  # 早停(为了加速训练)和自定义日志回调(看着方便)
    )
    
    # 预测测试集
    preds = gbm.predict(X_test)
    # 计算平均绝对误差
    mae = mean_absolute_error(y_test, preds)
    
    return mae  

# 创建一个Optuna的Study对象,目标为最小化评估指标
study = optuna.create_study(direction="minimize")
# 运行超参数优化,共100次试验
study.optimize(objective, n_trials=100)

# 获取最佳参数
best_params = study.best_params

# 使用最佳参数训练最终模型
model = lgb.LGBMRegressor(**best_params)
model.fit(X_train, y_train)  



其中,
使用Optuna进行超参数优化。
(Optuna是一个用于超参数优化的开源自动化调参框架,能帮助用户在机器学习模型训练过程中自动搜索最佳的超参数组合,从而提高模型的性能和泛化能力。其github主页:https://github.com/optuna/optuna)

objective函数定义了LightGBM模型的参数空间,并通过交叉验证计算模型的MAE。

最终结果如下:

最佳超参数:
lambda_l1: 2.9034541808996163e-07
lambda_l2: 0.0015926189116005033
num_leaves: 175
feature_fraction: 0.6628426546211686
bagging_fraction: 0.9696331544527079
bagging_freq: 4
min_child_samples: 14

最佳试验的MAE:
13.04939961067063

最终模型评估结果:

平均绝对误差(MAE):14.2566
特定范围内的平均绝对误差(Range MAE):11.3074
F1分数:0.7373
综合评分(Score):0.7557


分析和总结

可以看出,对lightgbm进行超参数调优后,模型的MAE和Range MAE都在可接受的范围内,表明模型在整体和特定范围内都有较好的预测性能。
而F1分数和综合评分较高,表明模型在低Remaining区间的分类和预测效果较好。
后续我将利用多模型的加权,即模型集成,结合特征工程,来进行更有效的优化。

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值