🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
所属专题:[字符串算法](README.md)   ## 问题 我们有一系列长度均为`$ n $`的DNA序列,它们的序列概况矩阵(profile matrix)是一个`$ 4\times n $`的矩阵`$ P $`. 其中,矩阵元素`$ P_{1,j} $`表示碱基A在各个序列的第`$ j $`位出现的次数;矩阵元素`$ P_{2,j} $`表示碱基C在各序列的第`$ j $`位出现的次数,以此类推。 一致性序列(consensus sequence)`$ c $`是一个长度同样为`$ n $`的序列,由我们所掌握的序列集合中,各个位置出现次数最多的元素所组成。因此,序列`$ c $`的第`$ j $`位对应于序列概况矩阵第`$ j $`列中元素值最大的那个符号(碱基/氨基酸)。当然,某些位置上可能有不止一个最常见的符号,这使得存在多个可能的一致性序列。 DNA序列、序列概况矩阵(profile matrix)、一致性序列(consensus sequence)的关系如下所示: ***** (1)多个等长的DNA序列: :-: A T C C A G C T G G G C A A C T A T G G A T C T A A G C A A C C T T G G A A C T A T G C C A T T A T G G C A C T (2)序列概况矩阵(profile matrix) :-: **A**    5 1 0 0 5 5 0 0    **C**    0 0 1 4 2 0 6 1    **G**    1 1 6 3 0 1 0 0    **T**    1 5 0 0 0 1 1 6    (3)一致性序列(consensus sequence) :-: A T G C A A C T **输入:** 包含多个等长的DNA序列的FASTA文件,序列不超过10条,长度均不超过1 kb. **输出:** 第一行是一致性序列,第二行至第五行是序列概况矩阵的内容。(如果存在多个一致性序列,则输出符合条件的任一个均可) **样例数据:** ~~~ >Rosalind_1 ATCCAGCT >Rosalind_2 GGGCAACT >Rosalind_3 ATGGATCT >Rosalind_4 AAGCAACC >Rosalind_5 TTGGAACT >Rosalind_6 ATGCCATT >Rosalind_7 ATGGCACT ~~~ **样例输出:** ~~~ ATGCAACT A: 5 1 0 0 5 5 0 0 C: 0 0 1 4 2 0 6 1 G: 1 1 6 3 0 1 0 0 T: 1 5 0 0 0 1 1 6 ~~~   ## 背景知识 该问题涉及序列概况矩阵与一致性序列的原理与应用。完成多序列比对后,通过构建序列概况矩阵,可以找到其中频数较高的序列组成模式;而一致性序列则是构建了一个平均情况下出现频率最高的序列组成,它代表了各个给定序列最相互接近的共同特征,这在序列的同源性分析中是很重要的概念。详情请查阅ROSALIND网站上[关于该问题的背景说明](http://rosalind.info/problems/cons/)。   ## 解答 ``` def read_fa(fa): """读入FASTA格式的文件对象fa,将其中的序列用字典结构存储""" seq = {} for line in fa: if line.startswith('>'): seqid = line.replace('>', '').strip() seq[seqid] = '' else: seq[seqid] += line.strip() return seq def profile_matrix(seq): """读入字典结构的多个序列,构建其Profile matrix""" sequences = list(seq.values()) seq_pos = list(zip(*sequences)) profile = {'A: ':[], 'C: ':[], 'G: ':[], 'T: ':[]} for pos in seq_pos: profile['A: '].append(pos.count('A')) profile['C: '].append(pos.count('C')) profile['G: '].append(pos.count('G')) profile['T: '].append(pos.count('T')) return profile def consensus_seq(seq): """读入字典结构的多个序列,构建一致性序列""" sequences = list(seq.values()) seq_pos = list(zip(*sequences)) base_freq = map(lambda x:dict((base, x.count(base)) for base in "ACGT"), seq_pos) conseq = ''.join([max(x, key=x.get) for x in base_freq]) return conseq ## --main-- with open("rosalind_cons.txt", 'r') as f1: dnaseqs = read_fa(f1) conseq = consensus_seq(dnaseqs) profile_m = profile_matrix(dnaseqs) with open("rosalind_cons_out.txt", 'w') as f2: f2.write(conseq + '\n') for base,profile in profile_m.items(): f2.write(base + ' '.join([str(x) for x in profile]) + '\n') ```