DataWhale夏令营 task2:深入理解赛题,入门RNN和特征工程

一、官方baseline分析

1.RNAModel类的forward方法中,展示了在得到序列特征的tensor表示后的处理步骤:

def forward(self, x):
    # 将输入序列传入嵌入层
    embedded = [self.embedding(seq) for seq in x]
    outputs = []
    ...

2.那么我们怎么能得到这个唯一标识呢?我们首先需要把序列给进行分词,siRNA_antisense_seq的分词策略是3个一组(GenomicTokenizer的ngram和stride都取3)进行token拆分,由此我们可以从整个数据集构建出一个词汇表,他负责token到唯一标识(索引)的映射:

# 创建词汇表
all_tokens = []
for col in columns:
    for seq in train_data[col]:
        if ' ' in seq:  # 修饰过的序列
            all_tokens.extend(seq.split())
        else:
            all_tokens.extend(tokenizer.tokenize(seq))
vocab = GenomicVocab.create(all_tokens, max_vocab=10000, min_freq=1)

3.有了这个词汇表,我们就可以

(1)来获得序列的最大长度

max_len = max(max(len(seq.split()) if ' ' in seq else len(tokenizer.tokenize(seq)) 
                    for seq in train_data[col]) for col in columns)

(2)- 在loader获取样本的时候把token转为索引

def __getitem__(self, idx):
    # 获取数据集中的第idx个样本
    row = self.df.iloc[idx]  # 获取第idx行数据
    
    # 对每一列进行分词和编码
    seqs = [self.tokenize_and_encode(row[col]) for col in self.columns]
    if self.is_test:
        # 仅返回编码后的序列(测试集模式)
        return seqs
    else:
        # 获取目标值并转换为张量(仅在非测试集模式下)
        target = torch.tensor(row['mRNA_remaining_pct'], dtype=torch.float)
        # 返回编码后的序列和目标值
        return seqs, target

def tokenize_and_encode(self, seq):
    if ' ' in seq:  # 修饰过的序列
        tokens = seq.split()  # 按空格分词
    else:  # 常规序列
        tokens = self.tokenizer.tokenize(seq)  # 使用分词器分词
    
    # 将token转换为索引,未知token使用0<pad>)
    encoded = [self.vocab.stoi.get(token, 0) for token in tokens]
    # 将序列填充到最大长度
    padded = encoded + [0] * (self.max_len - len(encoded))
    # 返回张量格式的序列
    return torch.tensor(padded[:self.max_len], dtype=torch.long)

二、RNN模型分析

1.上面已经得到了数据的张量化表示,此时就要把它输入模型了。

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

三、数据的特征工程

提交官方baseline后得分不佳,或因特征简单、序列构造粗糙、数据量不足。接下来,分享如何将序列特征转为表格问题,并介绍表格数据的特征工程技巧。

1.处理类别型变量

如何知道一个变量是类别型的呢,只需看下其值的分布,或者唯一值的个数。如果相较于数据的总行数很少,那么其很可能就是类别变量了,比如gene_target_symbol_name。此时,我们可以使用get_dummie函数来实现one-hot特征的构造。

# 如果有40个类别,那么会产生40列,如果第i行属于第j个类别,那么第j列第i行就是1,否则为0
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
]

2.可能的时间特征构造

siRNA_duplex_id_values = df.siRNA_duplex_id.str.split("-|\.").str[1].astype("int")

3.包含某些单词

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
]
# 包含Hepatocytes
df_cell_line_donor["feat_cell_line_donor_hepatocytes"] = (
    (df.cell_line_donor.str.contains("Hepatocytes")).fillna(False).astype("int")
)
# 包含Cells
df_cell_line_donor["feat_cell_line_donor_cells"] = (
    df.cell_line_donor.str.contains("Cells").fillna(False).astype("int")
)

4.根据序列模式提取特征

四、基于lightgbm的baseline

1.在得到了表格数据之后,我们可以使用任意适用于表格数据的机器学习回归模型来进行预测,此处我们简单使用了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],
)

说明:本文仅为个人学习笔记,仅供读者参考。代码、文字部分来源官方数据,如有侵权请联系删除。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值