siRNA药物药效预测(二)(Datawhale AI 夏令营)

一、task2解析

# 读取文件
df_original = pd.read_csv("data/train_data.csv")
# print(df_original)
# 获取原始训练数据的行数
n_original = df_original.shape[0]
# 读取数据
df_submit = pd.read_csv("data/sample_submission.csv")

# 合并两个数据集
# axis=0表示沿着行方向,即垂直方向,使用reset_index(drop=True)重置索引,drop=True参数意味着在重置索引时丢弃旧的索引
df = pd.concat([df_original, df_submit], axis=0).reset_index(drop=True)
# print(df)
def siRNA_feat_builder(s: pd.Series, anti: bool = False):
    # 变量定义
    name = "anti" if anti else "sense"
    df = s.to_frame()
    # 为每个序列计算长度,并作为新列添加到 DataFrame 中。
    df[f"feat_siRNA_{name}_seq_len"] = s.str.len()
    
    # 遍历序列的起始(0)和结束(-1)位置,以及字符 "A", "U", "G", "C"。
    # 对于每个位置和字符组合,检查序列在该位置是否为该字符,并将结果作为布尔值存储在新列中。
    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_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"
    )
    df[f"feat_siRNA_{name}_seq_pattern_9"] = s.str[1] == "A"
    df[f"feat_siRNA_{name}_seq_pattern_10"] = s.str[-2] == "A"
    
    # 使用 str.contains 方法检查序列中是否包含 "G" 或 "C",并计算这些字符的总数(注意这里假设 str.contains 返回布尔值,实际上在 pandas 中返回布尔 Series,但这里通过加法操作巧妙地转换为了整数值的和)
    # 然后将这个总数除以序列长度,得到 GC 含量的比例。
    df[f"feat_siRNA_{name}_seq_pattern_GC_frac"] = (
        s.str.contains("G") + s.str.contains("C")
    ) / s.str.len()
    
    # 函数返回 DataFrame df,但排除了第一列(即原始序列列),只返回计算得到的特征列。
    return df.iloc[:, 1:]
# 将分类变量(categorical variables)转换为独热编码(one-hot encoding)形式,以及对某些数值变量进行归一化处理

# 使用pd.get_dummies()函数将分类变量转换为独热编码。
# 独热编码是一种常用的处理分类数据的方法,它为每个类别创建一个新列,如果原始数据中的行属于该类别,则在该列中标记为1,否则为0
df_publication_id = pd.get_dummies(df.publication_id)
# 对于每个生成的独热编码DataFrame,代码还通过列表推导式重命名了列,以便在后续处理中更容易识别
# 例如,feat_publication_id_{c}表示publication_id特征的独热编码列,其中{c}是原始类别名称。
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列,通过字符串切片和类型转换提取并转换ID值。
siRNA_duplex_id_values = df.siRNA_duplex_id.str[3:-2].str.strip(".").astype("int")
# 然后,通过减去最小值并除以最大值与最小值之差(min-max normalization),将这些ID值归一化到0到1的范围内
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)

# 代码中特别为cell_line_donor列添加了两个新特征:feat_cell_line_donor_hepatocytes和feat_cell_line_donor_cells。
# 这是通过检查原始列中是否包含特定字符串("Hepatocytes"和"Cells")来实现的,如果包含,则相应的新特征列将被设置为1
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,
)
import lightgbm as lgb
from sklearn.model_selection import train_test_split

# 使用train_test_split函数对feats DataFrame进行分割。
X_train, X_test, y_train, y_test = train_test_split(
    # 这部分代码选择了feats DataFrame中的前n_original行和除了最后一列之外的所有列。这代表了特征集(X)
    # 不包括索引为n_original的行,因为Python的切片操作是左闭右开
    feats.iloc[:n_original, :-1],
    feats.iloc[:n_original, -1],
    # 测试集应该占总数据集的比例
    test_size=0.2,
    # 这个参数是一个随机种子,用于确保每次运行代码时分割的结果都是相同的。这有助于实验结果的可重复性。
    random_state=42,
)
# 使用X_train(特征数据)和y_train(目标变量)创建训练数据集
train_data = lgb.Dataset(X_train, label=y_train)
# 使用X_test和y_test创建测试数据集,并通过reference参数指定测试数据集与训练数据集共享相同的特征空间,即相同的列顺序和类型
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",    # 提升类型为GBDT
    "objective": "regression",  # 学习任务为回归
    "metric": "root_mean_squared_error",    # 评估模型性能的指标为均方根误差(RMSE)
    "max_depth": 7, # 树的最大深度为7
    "learning_rate": 0.02,  # 设置了学习率为0.02,较小的学习率意味着更慢的学习速度和更平滑的收敛
    "verbose": 0,   # 控制打印信息的详细程度,这里设置为0表示不打印训练过程中的信息(但回调函数会打印)
}
gbm = lgb.train(
    params,
    train_data, # 训练数据集
    num_boost_round=15000,  #迭代次数(即树的数量)为15000,
    # 实际使用时可能需要通过早停(early stopping)等方法来防止过拟合
    valid_sets=[test_data], # 指定了验证集为test_data
    callbacks=[print_validation_result],    # 指定了回调函数列表
)

注:GBDT(Gradient Boosting Decision Tree)是梯度提升类型的一种算法。它全称为梯度提升决策树,是一种迭代的决策树算法,通过构造一组弱的学习器(树),并把多棵决策树的结果累加起来作为最终的预测输出。在GBDT中,每棵树都是基于前面所有树的预测结果进行调整的,即每棵树都在学习如何预测前面所有树预测结果的残差(预测值与真实值之间的误差)。

# 预测结果赋值给变量y_pred
y_pred = gbm.predict(feats.iloc[n_original:, :-1])
df_submit["mRNA_remaining_pct"] = y_pred
df_submit.to_csv("submission.csv", index=False) # 参数index=False指定了在保存文件时不包括DataFrame的索引列

二,特征工程

1、引入新特征

1.1、对task2特征再刻画

对task2引入的长度、GC含量等特征细节刻画,引入生物知识先验

def siRNA_feat_builder3(s: pd.Series, anti: bool = False):  
    name = "anti" if anti else "sense"  
    df = s.to_frame()  
  
    # 长度分组  
    df[f"feat_siRNA_{name}_len21"] = (s.str.len() == 21)  
  
    # 省略号标识以此类推构造特征(示例:长度分组为20, 22)  
    df[f"feat_siRNA_{name}_len20"] = (s.str.len() == 20)  
    df[f"feat_siRNA_{name}_len22"] = (s.str.len() == 22)  
  
    # GC含量  
    GC_counts = (s.str.count("G") + s.str.count("C"))  
    lengths = s.str.len()  
    # 避免除以零  
    GC_frac = GC_counts / lengths  
    df[f"feat_siRNA_{name}_GC_in"] = (GC_frac >= 0.36) & (GC_frac <= 0.52)  
  
    # 局部GC含量(例如,位置1到7)  
    GC_counts1 = (s.str[1:7].str.count("G") + s.str[1:7].str.count("C"))  
    lengths1 = s.str[1:7].str.len()  
    # 对于长度小于7的序列,我们假设局部GC含量为NaN或0(取决于您希望如何处理)  
    GC_frac1 = GC_counts1 / lengths1  
    GC_frac1 = GC_frac1.fillna(0)  # 如果子序列长度小于7,则填充为0  
    df[f"feat_siRNA_{name}_GC_in1"] = GC_frac1  
  
    # 省略号标识的更多特征(示例:特定位置的字符)  
    df[f"feat_siRNA_{name}_first_char"] = s.str[0]  
    df[f"feat_siRNA_{name}_last_char"] = s.str[-1]  
  
    # 特定模式匹配(示例:以"AA"开头,以"UU"结尾)  
    df[f"feat_siRNA_{name}_pattern_AAUU"] = s.str.startswith("AA") & s.str.endswith("UU")  
  
    # 函数返回 DataFrame df,但排除了第一列(即原始序列列),只返回计算得到的特征列。  
    return df.iloc[:, 1:] 

1.2、修饰siRNA构建特征


voc_ls = ['A', 'U', 'G', 'C']  
  
def siRNA_feat_builder3_mod(s: pd.Series, anti: bool = False):  
    name = "anti" if anti else "sense"  
    df = pd.DataFrame(index=s.index)  # 使用序列的索引创建 DataFrame  
      
    # 初始化空列,以存储每个位置-核苷酸组合的特征  
    for pos in [0, -1, 1, -2]:  # 起始、终止和紧邻这些位置的单元  
        if pos == -2 and s.str.len().min() < 2:  # 检查序列长度以避免索引错误  
            continue  
        for c in voc_ls:  
            column_name = f"feat_siRNA_{name}_pos{pos}_{c}"  
            df[column_name] = False  # 初始化为 False  
      
    # 填充特征列  
    for idx, seq in s.items():  
        # 起始位置  
        if seq[0] in voc_ls:  
            df.at[idx, f"feat_siRNA_{name}_pos0_{seq[0]}"] = True  
        # 终止位置  
        if seq[-1] in voc_ls:  
            df.at[idx, f"feat_siRNA_{name}_pos-1_{seq[-1]}"] = True  
        # 紧邻起始位置  
        if len(seq) > 1 and seq[1] in voc_ls:  
            df.at[idx, f"feat_siRNA_{name}_pos1_{seq[1]}"] = True  
        # 紧邻终止位置(注意检查序列长度)  
        if len(seq) > 1 and seq[-2] in voc_ls:  
            df.at[idx, f"feat_siRNA_{name}_pos-2_{seq[-2]}"] = True  
      
    # 返回除了原始序列列之外的所有列(但这里没有原始序列列,因为我们没有添加它)  
    return df  

siRNA_feat_builder3_mod函数是一个用于处理RNA序列数据并生成特征DataFrame的实用工具。它接收一个pandas Series对象s作为输入,该对象包含了要分析的RNA序列,以及一个可选的布尔参数anti,用于指示正在处理的是正义链还是反义链。函数的主要目的是根据序列中特定位置(如起始、终止位置及其紧邻位置)的核苷酸类型,来构建一系列二进制特征。

函数首先根据anti参数的值,确定链的类型(正义或反义),并据此设置特征列名的前缀。然后,它创建一个新的pandas DataFrame,其索引与输入Series的索引相同,用于存储生成的特征。

接下来,函数遍历一个预定义的位置列表(包括起始、终止以及紧邻这些位置),并为每个位置上的每个可能核苷酸(从核苷酸列表voc_ls中获取)在DataFrame中初始化一个特征列,初始值均设为False。如果序列长度不足以支持对某个位置的访问(如位置-2且序列长度小于2),则跳过该位置的初始化。

之后,函数遍历输入Series中的每个序列,检查这些序列在特定位置上的核苷酸类型,并根据检查结果将相应的特征列值设置为True。这一过程涵盖了序列的起始位置、终止位置以及紧邻这些位置的单元。

最后,函数返回填充了所有特征值的DataFrame。这个DataFrame可以作为机器学习模型的输入,用于进一步分析或预测RNA序列的某些属性或功能。

需要注意的是,函数在实现时考虑了序列长度的限制,以避免索引错误,并且通过参数化链的类型(正义或反义),增加了函数的灵活性和可重用性。然而,它并未处理非核苷酸字符或空序列的情况,这在实际应用中可能需要额外的错误处理逻辑。

 

参考文章:

1、Datawhale (linklearner.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值