Datawhale AI 夏令营 ——Task2

竞赛流程与模型构建流程

竞赛流程通常包括以下几个阶段:

  1. 数据准备:下载数据,进行初步的探索性数据分析(EDA)。
  2. 特征工程:创建新特征,选择重要特征,进行特征缩放等。
  3. 模型选择:根据问题类型选择合适的模型,如RNN、CNN、决策树等。
  4. 模型训练:使用训练数据训练模型,调整超参数。
  5. 模型评估:使用验证集评估模型性能,进行交叉验证。
  6. 模型提交:将模型应用于测试集,生成提交文件。

深度学习是一种强大的机器学习技术,它通过使用多层神经网络来学习数据的复杂模式。RNN是一种适合于序列数据的深度学习模型,它能够捕捉时间序列中的动态特征。

  1. RNN的工作原理:RNN通过循环连接来处理序列中的每个元素,允许网络在处理当前元素时考虑之前的元素。
  2. 长短期记忆网络(LSTM):LSTM是RNN的一种变体,它通过门控机制解决了传统RNN的梯度消失问题。
  3. 门控循环单元(GRU):GRU是另一种RNN变体,它简化了LSTM的结构,但仍然能够有效地捕捉长期依赖关系。

RNN模型分析

class SiRNAModel(nn.Module):
    def __init__(self, vocab_size, embed_dim=200, hidden_dim=256, n_layers=3, dropout=0.5):
        super(SiRNAModel, self).__init__()
        
        # 初始化嵌入层
        self.embedding = nn.Embedding(vocab_size, embed_dim, padding_idx=0)
        # 初始化GRU层
        self.gru = nn.GRU(embed_dim, hidden_dim, n_layers, bidirectional=True, batch_first=True, dropout=dropout)
        # 初始化全连接层
        self.fc = nn.Linear(hidden_dim * 4, 1)  # hidden_dim * 4 因为GRU是双向的,有n_layers层
        # 初始化Dropout层
        self.dropout = nn.Dropout(dropout)
    
    def forward(self, x):
        # 将输入序列传入嵌入层
        embedded = [self.embedding(seq) for seq in x]
        outputs = []
        
        # 对每个嵌入的序列进行处理
        for embed in embedded:
            x, _ = self.gru(embed)  # 传入GRU层
            x = self.dropout(x[:, -1, :])  # 取最后一个隐藏状态,并进行dropout处理
            outputs.append(x)
        
        # 将所有序列的输出拼接起来
        x = torch.cat(outputs, dim=1)
        # 传入全连接层
        x = self.fc(x)
        # 返回结果
        return x.squeeze()

 

在构建深度学习模型的初期阶段,我们首先对索引进行了嵌入处理。嵌入(Embedding)是将离散的符号(例如单词、字符或基因序列片段)转换为连续向量的过程。这一过程通过将高维的稀疏表示(如独热编码)转换为低维的密集向量,使得语义上相似的符号在向量空间中彼此更接近。经过嵌入层后,数据的尺寸会从 BatchSize×LengthBatchSize×Length 变为 BatchSize×Length×EmbeddingSizeBatchSize×Length×EmbeddingSize,其中 EmbeddingSizeEmbeddingSize,也就是 embed_dim,被设置为200。

递归神经网络(Recurrent Neural Network, RNN)是一种特别擅长于处理序列数据的人工智能模型。与传统的神经网络不同,RNN能够捕捉到数据的时间动态特性。就像阅读书籍时,我们不仅理解当前阅读的内容,还会记住之前的情节,RNN利用先前的输入信息来更好地处理当前的输入。例如,在预测句子中下一个单词的任务中,RNN会根据已见过的单词序列(如“我今天早上吃了一个”)来预测下一个单词可能是“苹果”或“香蕉”。

然而,RNN在处理长序列时存在一些挑战:

  • 长期依赖问题:RNN可能难以利用很久之前的信息,因为随着序列的延长,早期的信息可能被后来的信息所覆盖或稀释。

  • 梯度消失和爆炸问题:在训练过程中,梯度可能会变得非常小(导致梯度消失)或非常大(导致梯度爆炸),这使得网络难以学习。

为了解决这些问题,长短期记忆网络(Long Short-Term Memory, LSTM) 引入了一种复杂的单元结构。LSTM包含三个门(输入门、遗忘门、输出门)和一个细胞状态,这些机制共同工作,使网络能够捕捉长期依赖关系:

  1. 输入门:决定多少当前信息将被写入细胞状态。

  2. 遗忘门:决定从细胞状态中丢弃多少旧信息。

  3. 输出门:决定细胞状态的哪一部分将被用作输出。

门控循环单元(Gated Recurrent Unit, GRU) 是LSTM的简化版本,它通过合并一些门来简化结构,但仍然保持了解决RNN问题的能力。GRU具有两个门:

  1. 更新门:决定当前状态与之前状态的更新程度。

  2. 重置门:决定需要忽略多少之前的信息。

在PyTorch中,GRU模型的参数配置对模型的输入输出张量维度至关重要,包括:

  • input_size(200)

  • hidden_size(256)

  • bidirectional(True)

假设输入的批量大小(Batch Size)为16,序列的最大长度为10,输入特征维度为200,则输入数据的尺寸为 16×10×20016×10×200。GRU模型的输出尺寸将是 16×10×(256×2)16×10×(256×2),这里的2表示模型是双向的。

在GRU模型输出后,我们通过 x = self.dropout(x[:, -1, :]) 获取序列中最后一个时间步的输出,此时输出尺寸变为 BatchSize×(hidden_dim×2)BatchSize×(hidden_dim×2)。如果我们需要将多个输出在特征维度上合并,可以使用 x = torch.cat(outputs, dim=1)。然后,通过一个全连接层将特征映射为标量。最后,使用 squeeze() 函数去除单维度,得到的张量尺寸将与批量大小相同,这样就可以与目标值进行损失计算,并用于模型的迭代训练。

数据特征工程

特征工程尤为重要,可以帮助模型更好地学习数据。

  1. 特征选择:选择与目标变量最相关的特征,避免过拟合。
  2. 特征构造:创建新的特征,如时间窗口统计、滚动平均等。
  3. 特征转换:对特征进行转换,如对数转换、标准化等,以提高模型性能。
  4. 特征编码:对类别型特征进行编码,如独热编码(One-Hot Encoding)。

在深入进行特征工程之前,我们首先要认识到,即使是官方的基线代码,也不一定能够达到令人满意的性能。这可能是由于所使用的特征过于基础,序列特征的构造不够精细,或者数据量不足以支撑深度学习模型,特别是RNN模型的学习。以下是对特征工程的深入探讨,包括将序列问题转化为表格问题的方法,以及在表格数据上进行特征工程的策略。

处理类别型变量

类别型变量的识别可以通过检查变量值的分布或唯一值的数量来完成。例如,在Pandas DataFrame中,可以使用nunique()方法来获取唯一值的个数,使用value_counts()来查看值的频率。如果一个变量相对于数据集的总行数具有很少的唯一值,那么它很可能是一个类别变量。对于这样的变量,我们可以使用pd.get_dummies()函数来实现One-Hot编码,从而将类别型变量转换为多个二进制列。

# 假设gene_target_symbol_name是类别变量 
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_{col}" for col in 
df['gene_target_symbol_name'].columns ]

构造时间特征

在观察数据时,我们可能会发现某些字段,如siRNA_duplex_id,具有特定的编码模式。这个字段可能包含类别信息、序列号和版本号。我们可以从这些字段中提取有意义的信息,构造新的时间特征。

# 假设siRNA_duplex_id包含序列号 
siRNA_duplex_id_values = df['siRNA_duplex_id'].str.split("-|\.").str[1].astype("int")

包含特定单词的特征

有时,某些特定的单词或短语在文本字段中的存在可能对模型预测有重要意义。我们可以通过检查这些单词是否存在于文本中来构造新的特征。

# 检查cell_line_donor字段中是否包含特定单词 df['feat_cell_line_donor_hepatocytes'] = (
df['cell_line_donor'].str.contains("Hepatocytes", na=False).astype("int") )
df['feat_cell_line_donor_cells'] = ( df['cell_line_donor'].str.contains("Cells", na=False).astype("int") )

根据序列模式提取特征

对于生物序列数据,如siRNA序列,我们可以根据RNA的背景知识来构造特征,例如序列的长度、特定的碱基模式、GC含量比例等。

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:]

特征工程是提高模型性能的关键步骤,通过对数据的深入理解和创造性地构造新特征,我们可以显著提升模型的预测能力。在实际操作中,我们应该不断尝试和验证新特征的有效性,以找到最佳的模型配置。

基于lightgbm的baseline

在得到了表格数据之后,我们可以使用任意适用于表格数据的机器学习回归模型来进行预测,此处我们简单使用了lightgbm模型:

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

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],
)

通过训练和修改参数得到:

提交分数:

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值