转眼又到了第三期结束了,这期的生物学难度挺大,涉及的专业很多,我的大多数时间不是在读懂baseline1和2的代码解读和帮助文档,就是在调参的路上。参加了上一期的学习有了部分代码运行和调参的经验,但是效果不太理想。每次的分数提高都不是很明显。
由于我对代码编写很不专业,所以好一部分的代码调整只能借助gpt来实现代码调整。通过听Task01与Task02的代码讲解明白了一部分。对于数据集里的特征序列的处理,作为非数值的文本特征需要经过特殊的编码才能对特征进行处理,这是比较难的一部分。task03对于这一部分处理的代码如下:
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]
if len(toks[-1]) < self.ngram:
toks = toks[:-1]
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)
# 处理序列特征
seq_features_df = pd.DataFrame()
tokenizer1 = GenomicTokenizer(ngram=1, stride=1) # 1gram
tokenizer2 = GenomicTokenizer(ngram=2, stride=1) # 2gram
tokenizer3 = GenomicTokenizer(ngram=3, stride=1) # 3gram
# 子串词频统计,未修饰序列
cols_nomod = ["siRNA_sense_seq", "siRNA_antisense_seq"]
all_tokens_nomod = []
for col in cols_nomod:
for seq in df[col]:
if pd.isna(seq):
continue
...
print('#all_tokens_nomod: ', len(all_tokens_nomod))
vocab_nomod = GenomicVocab.create(all_tokens_nomod, max_vocab=100000, min_freq=1)
print('#vocab_nomod: ', len(vocab_nomod.itos))
for col in cols_nomod:
...
# 子串词频统计,修饰序列
cols_mod = ["modified_siRNA_sense_seq", "modified_siRNA_antisense_seq"]
cols_mod_ls = ["modified_siRNA_sense_seq_list", "modified_siRNA_antisense_seq_list"]
all_tokens_mod = []
for col in cols_mod_ls:
for seq_ls in df[col]:
if pd.isna(seq_ls):
continue
...
print('#all_tokens_mod: ', len(all_tokens_mod))
vocab_mod = GenomicVocab.create(all_tokens_mod, max_vocab=100000, min_freq=1)
print('#vocab_mod: ', len(vocab_mod.itos))
for col in cols_mod:
因为Task03里面的代码为给完全,所以这段代码的实现需要借助Task01里面对于GenomicTokenizer和GenomicVocab的定义需要加入进来。
对于GC含量特征的处理,分享会的大佬说可以自己再加几条,我实在能力不允许加不进去。后续再学习这一部分的处理。代码如下:(有大神看到可以指导一下)这个应该要补充完整的,但是我只能用这一步去实现。省略号那里需要自己添加。
# GC含量
GC_frac = (s.str.count("G") + s.str.count("C")) / s.str.len()
df[f"feat_siRNA_{name}_GC_in"] = (GC_frac >= 0.36) & (GC_frac <= 0.52)
# 局部GC含量
GC_frac1 = (s.str[1:7].str.count("G") + s.str[1:7].str.count("C")) / s.str[1:7].str.len()
...
df[f"feat_siRNA_{name}_GC_in1"] = GC_frac1
...
return df.iloc[:, 1:]
对于这个步骤的实现也按照文案给的方法通过gpt帮我写了一段运行代码,不知道对不对。
实现如图所示siRNA序列与target序列的对比的代码如下,希望有大佬能指出错误。
def get_feat_align(df, anti: bool = False):
# 初始化一个用于存储得分的列表
scores = []
# 根据 anti 参数选择 siRNA 序列列名
siRNA_col = 'siRNA_antisense_seq' if anti else 'siRNA_sense_seq'
# 遍历 DataFrame 中的每一行
for idx, row in df.iterrows():
# 获取 siRNA 和 target 序列
siRNA_seq = row[siRNA_col]
target_seq = row['gene_target_seq']
# 进行局部比对,获取得分
alignments = pairwise2.align.localxx(siRNA_seq, target_seq)
# 从比对结果中取出最高得分
if alignments:
max_score = max(alignments, key=lambda x: x.score).score
scores.append(max_score)
else:
scores.append(0)
# 将得分列表添加到 DataFrame 中作为新列
df['alignment_score'] = scores
return df
这段代码是有用,我也未能证实。
特征这一部分按照指导思路,基本处理就结束了,其他我也是直接复制运行。后续就是调参了,真是人菜瘾大,不断地调,不断地修改参数,分数是升了降,降了升,而且浮动空间很小。来回蹦跶。下面是调参的一些参数,主要针对四个参数进行调整。如下表所示:
K折次数 | boost_round | max_depth | learning_rate | 官网提交得分 |
30 | 20000 | 8 | 0.01 | 0.8251 |
15 | 25000 | 8 | 0.01 | 0.8249 |
10 | 25000 | 8 | 0.05 | 0.8246 |
15 | 25000 | 8 | 0.01 | 0.8228 |
15 | 100000 | 8 | 0.01 | 0.8281 |
15 | 100000 | 8 | 0.05 | 0.8275 |
42 | 100000 | 8 | 0.05 | 0.8285 |
42 | 20000 | 8 | 0.02 | 0.8254 |
84 | 20000 | 8 | 0.05 | 0.8280 |
42 | 20000 | 8 | 0.08 | 0.8264 |
42 | 35000 | 8 | 0.01 | 0.8235 |
42 | 20000 | 7 | 0.1 | 0.8281 |
84 | 20000 | 7 | 0.1 | 0.8271 |
84 | 20000 | 7 | 0.2 | 0.8282 |
84 | 100000 | 7 | 0.005 | |
21 | 20000 | 7 | 0.1 | 0.8249 |
42 | 25000 | 8 | 0.05 | 0.8282 |
10 | 25000 | 8 | 0.05 | |
42 | 25000 | 8 | 0.05 | 0.8194 |
42 | 100000 | 7 | 0.1 |
花了好多时间,还是在0.82-0.829的区间徘徊。整不动了,过几天再整。外行整这个是在有点难搞呀!下次加油。会越来越厉害的。
谢谢Datawhale提供的平台,谢谢大家和助教的分享。