Datawhale Al夏令营——siRNA药物药效预测背景与Baseline
基本背景
目的
RNAi是生物体内天然存在的一种基因表达调控机制,通过抑制靶基因的表达来实现降低目标蛋白量的目的,这一机制一般可通过siRNA实现。本研究期望聚焦于通过机器学习技术,利用化学修饰后的siRNA序列来预测RNA干扰(RNAi)机制下对靶基因(target gene)的沉默效率,这一指标与药物实际疗效直接相关。
面临挑战
目前开源的数据库中,以RNA主干序列(裸序列)为主,缺少相应的化学修饰数据。而化学修饰对siRNA的毒性、体内稳定性、靶向效果、药效等具有重大影响,在实际药物设计中至关重要
原始资料
修饰后的siRNA数据非常稀缺,仅siRNAmod数据库包含4894条siRNA修饰序列。
基本数据集是通过对公开文献信息进行系统的整理、清洗、归一化后产生的,对多套化学修饰、细胞系、转染方式表达体系进行了统一整合,确保了数据的正确性、独特性和高应用价值,且数据量提升了1个数量级。
测试数据集由大睿生物提供部分尚未公开专利的siRNA修饰序列数据。
训练数据
train_data.csv
train_data.csv的每行为一条训练记录,包含数据记录的id、siRNA裸序列、相应的siRNA修饰序列、目标mRNA序列、siRNA浓度、细胞系、转染方法等实验室条件以及对应的实验室测量的mRNA Remaining值等总计19个字段。其中mRNA Remaining值为模型训练目标,其余18个字段的全部或部分可以作为模型的输入特征。
Remaining值代表了经过siRNA的沉默之后,mRNA的剩余百分比(相对于对照组)。Remaining值越低,siRNA的沉默效率越好,药效就越好。Remaining值一般位于0-100的区间内,100表示完全没有沉默效果,0表示该mRNA被彻底沉默,但是由于实验室测量的误差,可能存在少量训练记录的mRNA Remaining值在这个范围之外,这是正常的数据。
表头含义一览表:
表头字段 | 表头说明 |
---|---|
id | 数据唯一识别号 |
--- | --- |
publication_id | 公开文献号,已经过脱敏处理 |
gene_target_symbol_name | 靶基因符号名称,靶基因即为siRNA想要沉默的目标基因 |
gene_target_ncbi_id | 靶基因的NCBI标识 |
gene_target_species | 靶基因参考序列的物种,一般物种应为人类 |
siRNA_duplex_id | siRNA双链编号 |
siRNA_sense_seq | siRNA的sense序列 |
siRNA_antisense_seq | siRNA的antisense序列 |
cell_line_donor | 实验使用的细胞系,一般认为对沉默效率测定存在较大影响 |
siRNA_concentration | 实验使用的siRNA浓度,一般认为对沉默效率测定存在较大影响 |
concentration_unit | siRNA浓度单位,比如nM |
Transfection_method | 转染方法,即将siRNA植入细胞的方法,一般认为对沉默效率测定存在较大影响 |
Duration_after_transfection_h | 转染后持续时间(小时) |
modified_siRNA_sense_seq | 带修饰的siRNA的sense序列 |
modified_siRNA_antisense_seq | 带修饰的siRNA的antisense序列 |
modified_siRNA_sense_seq_list | 带修饰的siRNA的sense序列分解列表,基于标准词表将sense序列分解,以空格分隔 |
modified_siRNA_antisense_seq_list | 带修饰的siRNA的antisense序列分解列表,基于标准词表将antisense序列分解,以空格分隔 |
gene_target_seq | 靶基因的参考序列,siRNA一般靶向序列中的一部分片段以达到沉默的效果 |
mRNA_remaining_pct | 实验后mRNA的剩余百分比 |
sample_submission.csv
sample_submission.csv为初赛的leaderboard submission测试集,格式与初赛训练集train_data.csv相同。不同之处在于mRNA_remaining_pct列的数值为空,参赛者需要填充这些空白处的预测结果后提交。
"leaderboard submission测试集" 指的是一个特定的数据集,它用于评估参赛者在某个竞赛中的表现。
vocab.csv(经过归一化后的siRNA化学修饰缩写表)
第一列(Abbreviation):列出了各种修饰核苷酸的缩写。
第二列(Chemical Name):展示了与第一列中缩写对应的完整化学名称。这些化学名称详细描述了核苷酸的结构,包括对其进行的化学修饰。这些修饰可能涉及改变核苷酸的糖部分、磷酸基团或碱基,以增强其性能,如提高稳定性或特定的生物活性。
样例数据
Abbreviation | Chemical Name |
---|---|
A | adenosine-3'-phosphate |
--- | --- |
C | cytidine-3'-phosphate |
G | guanosine-3'-phosphate |
baseline.py
本次比赛提供一个基础的基线方法,利用 RNN 来预测Remaining值。基线方法中我们仅使用了siRNA_sense_seq 字段作为特征,除此之外尚有其他特征对Remaining结果有重大影响。
评价指标
本次任务采用3个指标来进行评测
- 平均绝对误差(MAE):平均绝对误差是对每个样本的绝对误差取平均值,主要用于衡量模型在整体上的预测精度。𝑦𝑖yi为实验室的真实测量值,𝑦𝑖yi为模型的预测值,计算公式 MAE=1𝑛∑𝑖=1𝑛∣𝑦𝑖-𝑦𝑖∣MAE=n1∑i=1n∣yi-yi∣,其中𝑛n是样本总数,MAE∈[0,100]MAE∈[0,100]。
- 预测值在一定范围内的平均绝对误差(Range-MAE):在实际场景我们会尤其关注在低Remaining区间模型的预测准确率,此指标衡量在特定范围内的预测值的平均绝对误差。在本次比赛中,低Remaining范围为[0,30][0,30],计算公式 Range-MAE=1𝑚∑𝑖=1𝑚∣𝑦𝑖-𝑦𝑖∣Range-MAE=m1∑i=1m∣yi-yi∣,其中𝑚m是预测值在[0,30][0,30]范围内的样本数量,Range-MAE∈[0,100]Range-MAE∈[0,100]。
- 预测值在一定范围内的F1指标(F1):此指标衡量在特定范围内的预测值的precision以及在相应区间预测的recall情况,综合得到F1值。在本次比赛中,低Remaining范围为[0,30][0,30]。
解读baseline
1、为什么要self.ngram = ngram,而不是直接赋值
定义实例属性使得类(class)的其他方法(其他def)可以直接访问和使用 ngram 的值。例如,tokenize 方法需要使用 ngram 的值来执行分词操作,如果不将其定义为实例属性,就无法在 tokenize 方法中直接访问。
class GenomicTokenizer:
def __init__(self, ngram=5, stride=2):
self.ngram = ngram
self.stride = stride
# 假设使用实例属性
def tokenize(self, t):
t = t.upper()
if self.ngram == 1:
toks = list(t)
else:
toks = [t[i:i+self.ngram] for i in range(0, len(t), self.stride) if len(t[i:i+self.ngram]) == self.ngram]
return toks
# 假设不使用实例属性,而是硬编码
def tokenize(self, t):
t = t.upper()
ngram = 5
stride = 2
if ngram == 1:
toks = list(t)
else:
toks = [t[i:i+ngram] for i in range(0, len(t), stride) if len(t[i:i+ngram]) == ngram]
return toks
2、列表推导式
列表推导式(List Comprehension)是一种在Python中用来创建列表的简洁语法。它允许你从一个序列(如列表、元组、字符串等)或者另一个列表推导式,通过一个表达式来生成新的列表。列表推导式通常包含一个表达式,后面跟着一个for循环,以及可选的if条件语句。
基本语法如下:
[expression for item in iterable if condition]
expression
是对每个元素进行的操作。item
是从iterable
中取出来的元素。iterable
是一个序列或者任何可迭代的对象。condition
是一个可选的条件语句,用于筛选元素。
例如,如果你有一个数字列表,你想创建一个新的列表,其中只包含原列表中的偶数,你可以使用列表推导式如下:
original_list = [1, 2, 3, 4, 5, 6]
even_numbers = [num for num in original_list if num % 2 == 0]
在这个例子中,even_numbers
将会是 [2, 4, 6]
。
3、类方法和实例方法
"类方法"和"实例方法"是面向对象编程中的两个概念,它们都与类和对象的行为有关,但它们的使用场景和作用不同。
-
实例方法:这是最常见的方法类型,它们与类的实例(对象)相关联。实例方法的第一个参数通常是
self
,它代表当前对象的实例。当调用实例方法时,你通常是在对某个具体的对象进行操作。 -
类方法:与实例方法不同,类方法是与类本身相关联的方法。这意味着它们不需要创建类的实例就可以被调用。类方法的第一个参数通常是
cls
,它代表类本身。使用类方法可以访问类属性或执行与类相关的操作,而不需要创建类的实例。
在Python中,使用 @classmethod
装饰器来定义一个类方法。这个装饰器告诉Python解释器,接下来的函数是一个类方法,而不是一个实例方法。当你调用一个类方法时,你可以使用类名直接调用,也可以通过类的实例调用,但传递给方法的第一个参数将是类本身,而不是实例。
在Python中,类方法和实例方法的区别可以通过一个实际案例来更清晰地理解:
为了更好地理解类方法和实例方法的区别及其用途,下面是一个具体的例子。假设我们在开发一个员工管理系统,我们需要管理员工的信息并生成员工的工号。
实例方法
实例方法依赖于类的实例(对象),它们操作实例数据。实例方法的第一个参数通常是 self
,表示实例本身。
class Employee:
def __init__(self, name, age):
self.name = name
self.age = age
self.employee_id = None
def set_employee_id(self, employee_id):
self.employee_id = employee_id
def get_info(self):
return f"Name: {self.name}, Age: {self.age}, Employee ID: {self.employee_id}"
使用实例方法
# 创建员工实例
emp1 = Employee("Alice", 30)
emp2 = Employee("Bob", 35)
# 设置员工ID
emp1.set_employee_id("E001")
emp2.set_employee_id("E002")
# 获取员工信息
print(emp1.get_info()) # 输出: Name: Alice, Age: 30, Employee ID: E001
print(emp2.get_info()) # 输出: Name: Bob, Age: 35, Employee ID: E002
在这个例子中:
set_employee_id
和get_info
是实例方法,它们操作和访问实例的数据(name
、age
和employee_id
)。- 每个实例(
emp1
和emp2
)都有独立的数据。
类方法
类方法不依赖于类的实例,它们操作类本身的数据或提供一些通用功能。类方法的第一个参数通常是 cls
,表示类本身。
class Employee:
employee_count = 0 # 类变量,所有实例共享
def __init__(self, name, age):
self.name = name
self.age = age
self.employee_id = None
Employee.employee_count += 1
def set_employee_id(self, employee_id):
self.employee_id = employee_id
def get_info(self):
return f"Name: {self.name}, Age: {self.age}, Employee ID: {self.employee_id}"
@classmethod
def generate_employee_id(cls):
return f"E{cls.employee_count + 1:03d}"
使用类方法
# 创建员工实例
emp1 = Employee("Alice", 30)
emp2 = Employee("Bob", 35)
# 使用类方法生成员工ID
emp1.set_employee_id(Employee.generate_employee_id())
emp2.set_employee_id(Employee.generate_employee_id())
# 获取员工信息
print(emp1.get_info()) # 输出: Name: Alice, Age: 30, Employee ID: E003
print(emp2.get_info()) # 输出: Name: Bob, Age: 35, Employee ID: E004
# 查看总员工数
print(Employee.employee_count) # 输出: 2
在这个例子中:
generate_employee_id
是一个类方法,它不依赖于具体的实例,而是依赖于类的数据(employee_count
)。employee_count
是一个类变量,所有实例共享,用于跟踪员工的总数。
区分类方法和实例方法
-
作用域不同:
- 实例方法作用于类的实例,操作实例数据。
- 类方法作用于类本身,操作类的数据或提供一些通用功能。
-
使用场景不同:
- 当需要访问或修改实例的属性时,使用实例方法。
- 当需要执行与类相关的操作且不依赖于实例数据时,使用类方法。例如,统计类的实例数量、生成唯一的实例标识符等。
-
设计上的清晰性和组织性:
- 将不同类型的方法分开,可以使代码更清晰、更易于维护。类方法适用于全局操作或类级别的操作,实例方法适用于具体实例的操作。