#Datawhale AI夏令营 之 AI for Science(AI+药物)#深度学习 #task 2

task2 深入理解赛题,入门RNN和特征工程

前面我们了解了task1和和一些基础知识,那么task2就直接步入正题了

思路:我们应该关注哪些部分?

  • 第一部分:关注模型从原始特征到输入模型之前应该经历哪些过程,
  • 第二部分:关注输入模型后到输出经历哪些过程,
  • 第三部分:关注输入输出后,输出和训练集的真实值计算损失。

第一部分 :

### 5. siRNA Model

这是一个基于GRU的神经网络模型,用于处理siRNA序列。

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

我们可以发现输入是通过forward函数实现的,那么x是什么呢, 跳转到第八部分中有一个对数据集的拆分然后进行迭代的循环

for epoch in range(num_epochs):
        model.train()  # 设置模型为训练模式
        train_loss = 0  # 初始化训练损失
        for inputs, targets in tqdm(train_loader, desc=f'Epoch {epoch+1}/{num_epochs}'):
            inputs = [x.to(device) for x in inputs]  # 将输入移动到设备
            targets = targets.to(device)  # 将目标值移动到设备

 这时候可以查看一下inputs的维度,通过在输出调用train_model之前,打印一下train_loder中的输入尺寸

for inputs, target in train_loader:
    print(len(inputs))
    print(inputs[0].shape)
    print(inputs[0][0])
    print(target.shape)
    break

   

 打印出来后可以发现这个inputs这个列表里元素张量的维度为64*25,这里的inputs和上面的x是一个东西。我们首先发现inputs包含两个元素,它们分别对应的是前面提到的两个使用的特征,每个元素的尺寸都是64*25,64代表batch的大小,25代表序列的长度。这里我们可以从inputs[0][0]看到每一行数据的siRNA_antisense_seq被向量化后的情况,这个例子中我们发现前面的7位是非零数,表示其序列编码后每一位的唯一标识;而后面都是0,这是因为RNN模型的输入需要每个样本的长度一致,因此我们需要事先算出一个所有序列编码后的最大长度,然后补0。

那么我们怎么能得到这个唯一标识呢?我们首先需要把序列给进行分词,siRNA_antisense_seq的分词策略是3个一组(GenomicTokenizer的ngram和stride都取3)进行token拆分,比如AGCCGAGAU会被分为[AGC, CGA, GAU],而modified_siRNA_antisense_seq_list会进行按照空格分词(因为它本身已经根据空格分好了)。由此我们可以从整个数据集构建出一个词汇表,他负责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)

有了这个词汇表,我们就可以来获得序列的最大长度


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)

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

(补充一下补0操作,假如我现在有60长度的碱基序列,token编码后得出序列最大长度为25,此时,每一段为长度为20(20<25),就需要在后面补5个0 )

例如此时,对于某一行数据,其两个特征分别为AGCCUUAGCACA和u u g g u u Cf c,假设整个数据集对应token编码后序列的最大长度为10,那么得到的特征就可能是

  • [25, 38, 25, 24, 0, 0, 0, 0, 0, 0]

  • [65, 65, 63, 63, 65, 65, 74, 50, 0, 0]

那么假设batch的大小为16,此时forword函数的x就会是两个列表,每个列表的tensor尺寸为16 * 10

第二部分 :

我们在上一部分已经得到了数据的张量化表示,此时就要把它输入模型了。

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,token的embedding是将离散的符号(如单词、字符、或基因序列片段)映射到连续的向量空间的过程。这个过程通过将高维的稀疏表示(如独热编码)转换为低维的密集向量表示,使得相似的符号在向量空间中距离更近。此时,embed的尺寸会从BatchSize * Length成为BatchSize * Length * EmbeddingSize,此处EmbeddingSize即embed_dim=200。 

然后了解一下RNN、LSTM与GRU的工作原理和流程:RNN、LSTM和GRU_lstm gru rnn-CSDN博客

下面是一些特点

RNN(Recurrent Neural Network)模型

定义: RNN是一种特殊的神经网络,适合处理序列数据。与传统的前馈神经网络不同,RNN具有内部状态(记忆),能够处理输入信息的序列,这使得它们非常适合处理语言处理、时间序列分析等任务。

结构特点:

  • 循环结构: RNN的核心是循环单元,该单元能够将信息传递到下一个时间步,从而创建状态序列。
  • 参数共享: 在处理序列的不同时间步时,RNN使用相同的权重,这减少了模型的参数数量。

优点:

  • 处理序列数据: 能够处理任意长度的序列数据。
  • 参数共享: 减少了模型的参数数量,降低了计算复杂度。

缺点:

  • 梯度消失和梯度爆炸: 在长序列中,RNN很难捕捉到长距离依赖,因为梯度在反向传播过程中可能消失或爆炸。
  • 难以并行化: 由于序列依赖性,RNN的计算通常需要按顺序进行,这限制了并行处理的能力。

LSTM(Long Short-Term Memory)

定义: LSTM是RNN的一种变体,由Hochreiter和Schmidhuber在1997年提出,旨在解决标准RNN在长序列学习中遇到的梯度消失问题。

结构特点:

  • 门结构: LSTM单元包含三个门(输入门、遗忘门、输出门)和一个细胞状态,这些结构允许LSTM单元有选择性地记住或忘记信息。
  • 细胞状态: LSTM单元的核心,它可以在序列中传递信息,使得LSTM能够捕捉长距离依赖。

优点:

  • 解决梯度消失问题: LSTM通过门控机制和细胞状态有效地解决了梯度消失问题,能够学习长序列的依赖关系。
  • 更灵活的记忆: LSTM能够根据需要记住或忘记信息,这使得它在处理不同长度的序列时更为灵活。

GRU(Gated Recurrent Unit)

定义: GRU是由Cho等人在2014年提出的一种RNN的变体,它和LSTM一样,旨在解决标准RNN在处理长序列时遇到的梯度消失问题。GRU可以看作是LSTM的一个简化版本,它具有更少的门控结构。

结构特点:

  • 重置门和更新门: GRU只有两个门,分别是重置门(reset gate)和更新门(update gate)。这两个门控制信息的流动。
  • 隐藏状态: GRU没有单独的长期记忆细胞状态,而是将隐藏状态和细胞状态合并为一个单一的隐藏状态。

优点:

  • 更少的参数: 相比于LSTM,GRU的参数更少,这使得模型的计算效率更高,训练速度更快。
  • 简化结构: GRU的门控结构比LSTM简单,这使得模型更容易理解和实现。
  • 缓解梯度消失问题: 类似于LSTM,GRU通过门控机制能够缓解梯度消失问题,学习长序列的依赖关系。

GRU 的结构更简单,计算效率更高,同时在许多应用中表现出与 LSTM 类似的性能。

我们在pytorch的GRU文档中可以找到对应可选的参数信息,我们需要特别关注的参数如下,它们决定了模型的输入输出的张量维度

  • input_size(200)

  • hidden_size(256)

  • bidirectional(True)

假设输入的BatchSize为16,序列最大长度为10,即x每个元素尺寸为16 * 10 * 200,那么其输出的张量尺寸为 16 * 10 * (256 * 2)

在从GRU模型输出后,x = self.dropout(x[:, -1, :])使得输出变为了BatchSize * (hidden_dim * 2),此处取了序列最后一个位置的输出数据(注意RNN网络的记忆性),这里的2是因为bidirectional参数为True,随后x = torch.cat(outputs, dim=1)指定在第二个维度拼接后,通过全连接层再映射为标量,因此最后经过squeeze(去除维数为1的维度)后得到的张量尺寸为批大小,从而可以后续和target值进行loss计算,迭代模型

做完后我们发现效果并不是很好,,这一方面原因可能在于数据用的特征还较为简单,序列特征的构造较为粗糙,下面进行在表格数据上做特征工程(lightgbm模型)。

在特征构造前,一定要分析数据,我们先展示一下一共有多少列,然后判断这个变量是类别变量还是数值型变量,如果是数值型变量(例如上一期的电力预测里的变量)就需要考虑方差,均值的分布,如果是类别型变量就要考虑有多少类别数,分别占比等等.

可以用下面语句先展示一下一共有多少列

df.columns

我们就拿publication_id来举例,(pandas库中,.value_counts() 是一个非常有用的方法,它用于计算Series(一维数组)中各个值的频率,并返回一个按频率降序排列的Series。这对于快速查看数据集中不同值的分布情况非常有用。)

df.publication_id.value_counts()

如果相较于数据的总行数很少,那么其很可能就是类别变量了。此时,我们可以使用get_dummie函数来实现one-hot特征的构造(pandas库中,get_dummies() 函数是用来创建一个one-hot编码(独热编码)的DataFrame。One-hot编码是一种将分类变量转换为二进制(0和1)向量表示的方法,其中每个向量只有一个元素为1,其余元素为0。),siRNA和mRNA序列本质上是分类数据,每个碱基(A、U、C、G)都是一个类别。通过One-hot编码,可以将这些碱基转换成数值特征向量,并且除了碱基序列,还可能考虑其他特征,如GC含量、序列的二级结构、靶标mRNA的局部结构等。这些特征可以通过One-hot编码转换成机器学习模型可以理解的格式

举个例子:

import pandas as pd
 
data = {'颜色': ['红色', '绿色', '蓝色', '红色']}
df = pd.DataFrame(data)
 
# 进行One-hot编码
encoded_df = pd.get_dummies(df['颜色'])
 
print(encoded_df)

结果就是:

   红色  绿色  蓝色
0    1    0    0
1    0    1    0
2    0    0    1
3    1    0    0

结果我们发现有很多列都是分类变量,处理方法也都是一样的:

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
]
siRNA_duplex_id_values = df.siRNA_duplex_id.str[3:-2].str.strip(".").astype("int")
siRNA_duplex_id_values = (siRNA_duplex_id_values - siRNA_duplex_id_values.min()) / (
    siRNA_duplex_id_values.max() - siRNA_duplex_id_values.min()
)
df_siRNA_duplex_id = pd.DataFrame(siRNA_duplex_id_values)
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")
)
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}"

在数据观察的时候发现,siRNA_duplex_id的编码方式很有意思,其格式为AD-1810676.1,我们猜测AD是某个类别,后面的.1是版本,当中的可能是按照一定顺序的序列号,因此可以构造如下可能的时间特征

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

在观察 cell_line_donor的时候同样发现,他们一共有两种的后缀(Hepatocytes和Cells),我们猜测可能与二分类有关,因此可以构造如下特征

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

根据序列模式提取特征

假设siRNA的序列为ACGCA...,此时我们可以根据上一个task中提到的rna背景知识,对碱基的模式进行特征构造

ef 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模型:

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

这里有一些好的调参建议(各位可以参考) 

https://lightgbm.readthedocs.io/en/stable/Parameters.html

以上就是task2的学习过程辣~最后分数也来到了0.7590~hh

其实大家经过调参也可以进行一定的分数提升,修改一些num_boost_round(迭代次数)学习速率(learning_rate),树的深度(max_depth).....

也可以加一些新的特征(

df[f"feat_siRNA_{name}_seq_pattern_1"] = s.str.startswith("AAA") & s.str.endswith("UUU")

df[f"feat_siRNA_{name}_seq_pattern_5"] = s.str.startswith("UUU") & s.str.endswith("AAA")

我加上了连续“AAA”“UUU”这样的特征,分数都是有些许提高的,本人是一名小白,上文有借助检索解决疑惑和一些自己的理解,如有不对的地方还请各位大佬提出,会修改的hh,期待task3的学习qwq(有部分理解源自b站二次元的Datawhale巨佬耿远昊的讲解,大家可以点击链接观看

二次元的Datawhale

完整baseline 代码

import pandas as pd


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


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


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
]
siRNA_duplex_id_values = df.siRNA_duplex_id.str[3:-2].str.strip(".").astype("int")
siRNA_duplex_id_values = (siRNA_duplex_id_values - siRNA_duplex_id_values.min()) / (
    siRNA_duplex_id_values.max() - siRNA_duplex_id_values.min()
)
df_siRNA_duplex_id = pd.DataFrame(siRNA_duplex_id_values)
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")
)
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
]
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,
)


!pip install lightgbm

import lightgbm as lgb
from sklearn.model_selection import train_test_split

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)


# 定义一个回调函数来打印验证集的结果
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],
)

y_pred = gbm.predict(feats.iloc[n_original:, :-1])

df_submit["mRNA_remaining_pct"] = y_pred
df_submit.to_csv("submission.csv", index=False)

  • 11
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值