入门RNN与特征工程
在这篇文章中,我将首先对官方提供的baseline进行分析,之后介绍RNN的基础知识以及在特征工程中的应用。最后,我将结合lightGBM模型,提出一个更优化的baseline。
baseline分析
官方提供的baseline模型仅使用了两个特征:siRNA_antisense_seq和modified_siRNA_antisense_seq_list。为了让这些序列特征能够输入到RNN模型中,我们首先需要对它们进行处理。在模型的forward
方法中,我们可以看到序列特征经过向量化处理后的情况:
def forward(self, x):
# 将输入序列传入嵌入层
embedded = [self.embedding(seq) for seq in x]
outputs = []
for embed in embedded:
x, _ = self.gru(embed)
x = self.dropout(x[:, -1, :])
outputs.append(x)
x = torch.cat(outputs, dim=1)
x = self.fc(x)
return x.squeeze()
此处的输入x
是通过数据加载器(train_loader
)生成的,它包含两个元素,每个元素对应一个特征。每个元素的尺寸是[64, 25]
,表示batch大小为64,序列长度为25。为了使这些序列特征适应RNN模型的输入要求,我们首先对它们进行分词和编码。
以下是分词和编码的部分代码:
class GenomicTokenizer:
def __init__(self, ngram=3, stride=3):
self.ngram = ngram
self.stride = stride
def tokenize(self, t):
t = t.upper()
toks = [t[i:i+self.ngram] for i in range(0, len(t), self.stride)]
return toks
class GenomicVocab:
def __init__(self, itos):
self.itos = itos
self.stoi = {v: k for k, v in enumerate(self.itos)}
@classmethod
def create(cls, tokens, max_vocab, min_freq):
freq = Counter(tokens)
itos = ['<pad>'] + [o for o, c in freq.most_common(max_vocab - 1) if c >= min_freq]
return cls(itos)
# 构建词汇表
tokenizer = GenomicTokenizer()
all_tokens = []
for seq in train_data['siRNA_antisense_seq']:
all_tokens.extend(tokenizer.tokenize(seq))
vocab = GenomicVocab.create(all_tokens, max_vocab=10000, min_freq=1)
RNN模型解析
RNN模型在处理序列数据时非常有效,它通过递归的结构记忆之前的信息,来预测当前的输出。以下是GRU的定义及其在模型中的使用:
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)
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)
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)
x = self.dropout(x[:, -1, :])
outputs.append(x)
x = torch.cat(outputs, dim=1)
x = self.fc(x)
return x.squeeze()
GRU(门控循环单元)通过使用更新门和重置门,解决了传统RNN在处理长序列数据时的长期依赖和梯度消失问题。
特征工程
在提高模型性能的过程中,特征工程是关键一步。我通过处理类别型变量、时间特征、序列特征等多个方面优化了数据输入。例如,对于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_{c}" for c in df_gene_target_symbol_name.columns]
对于siRNA序列,我们提取了一些生物学上相关的特征:
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"):
df[f"feat_siRNA_{name}_seq_{c}_{'front' if pos == 0 else 'back'}"] = (s.str[pos] == c)
df[f"feat_siRNA_{name}_seq_pattern_GC_frac"] = (s.str.count("G") + s.str.count("C")) / s.str.len()
return df.iloc[:, 1:]
这些特征帮助我们更好地理解数据背后的生物机制,从而提升模型的预测能力。
基于lightGBM的优化模型
在处理完特征工程后,我选择使用lightGBM模型来进行预测。lightGBM在处理大规模数据和高维数据时表现出色。以下是模型训练的部分代码:
import lightgbm as lgb
train_data = lgb.Dataset(X_train, label=y_train)
test_data = lgb.Dataset(X_test, label=y_test, reference=train_data)
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])
结语
在之前的工作中,我们已经探索了化学修饰对siRNA序列功能的影响,这次我们更深入地挖掘了序列特征,并结合了机器学习中的先进技术,如RNN和lightGBM。这些探索不仅帮助我们理解了特征工程在药效预测中的重要性,也展示了多模态数据融合的潜力。
未来,我们计划继续深化特征的研究,特别是在多模态数据的整合方面,例如结合更多的生物信息学数据,以进一步提高预测的精度。此外,我们还将尝试更先进的深度学习架构,如Transformer,以处理更复杂的序列数据。这些努力旨在为siRNA药物的设计和优化提供更加全面的工具和方法。我们期待这些进展能为核酸药物研发领域带来更多突破性的成果。
如果你觉得这篇博文对你有帮助,请点赞、收藏、关注我,并且可以打赏支持我!
欢迎关注我的后续博文,我将分享更多关于人工智能、自然语言处理和计算机视觉的精彩内容。
谢谢大家的支持!