第8章 BLAST和其他序列搜索工具(实验性质的代码)¶
WARNING: 这章教程介绍了Biopython中一个 实验的 模块。它正在被加入到
Biopython中,并且以一个预尾期的状态整理到教程当中,这样在我们发布稳定版
的之前可以收到一系列的反馈和并作改进。那时有些细节可能会改变,并且用到
当前 Bio.SearchIO
模块的脚本也需要更新。切记!为了与NCBI BLAST有关的
代码可以稳定工作,请继续使用第 7 章介绍的Bio.Blast。
生物序列的鉴定是生物信息工作的主要部分。有几个工具像BLAST(可能是最流行 的),FASTA ,HMMER还有许多其它的都有这个功能,每个工具都有独特的算法和 途径。一般来说,这些工具都是用你的序列在数据库中搜索可能的匹配。随着序列 数量的增加(匹配数也会随之增加),将会有成百上千的可能匹配,解析这些结果 无疑变得越来越困难。理所当然,人工解析搜索结果变得不可能。而且你可能会同 时用几种不同的搜索工具,每种工具都有独特的统计方法、规则和输出格式。可以 想象,同时用多种工具搜索多条序列是多么恐怖的事。
我们对此非常了解,所以我们在Biopython构建了 Bio.SearchIO
亚模块。Bio.SearchIO
模块使从搜索结果中提取信息变得简单,并且可以处理不同工具
的不同标准和规则。SearchIO
和BioPerl中模块名称一致。
在本章中,我们将学习 Bio.SearchIO
的主要功能,了解它可以做什么。我
们将使用两个主要的搜索工具:BLAST和FASTA。它们只是用来阐明思路,你可以轻
易地把工作流程应用到 Bio.SearchIO
支持的其他工具中。欢迎你使用我们将要
用到的搜索结果文件。BLAST搜索结果文件可以在
这里 下载。
BLAT输出结果文件可以在
这里 下载。两个结果
文件都是用下面这条序列搜索产生的:
>mystery_seq
CCCTCTACAGGGAAGCGCTTTCTGTTGTCTGAAAGAAAAGAAAGTGCTTCCTTTTAGAGGG
BLAST的XML结果是用 blastn
搜索NCBI的 refseq_rna
数据库得到的。对于
BLAT,数据库是2009年2月份的 hg19
人类基因组草图,输出格式是PSL。
我们从 Bio.SearchIO
的对象模型的介绍开始。这个模型代表你的搜索结果,因
此它是 Bio.SearchIO
的核心。然后,我们会介绍 Bio.SearchIO
常用的主要
功能。
现在一切就绪,让我们开始第一步:介绍核心对象模型。
8.1 SearchIO对象模型¶
尽管多数搜索工具的输出风格极为不同,但是它们蕴含的理念很相似:
- 输出文件可能包含一条或更多的搜索查询的结果。
- 在每次查询中,你会在给定的数据库中得到一个或更多的hit(命中)。
- 在每个hit中,你会得到一个或更多包含query(查询)序列和数据库序列实际比对的区域。
- 一些工具如BLAT和Exonerate可能会把这些区域分成几个比对片段(或在BLAT中 称为区块,在Exonerate中称为可能外显子)。这并不是很常见,像BLAST和 HMMER就不这么做。
知道这些共性之后,我们决定把它们作为创造 Bio.SearchIO
对象模型的基础。对
象模型是Python对象组成的嵌套分级系统,每个对象都代表一个上面列出的概念。这些对
象是:
QueryResult
,代表单个搜索查询。Hit
,代表单个的数据库hit。Hit
对象包含在QueryResult
中, 每个QueryResult
中有0个或多个Hit
对象。HSP
(high-scoring pair(高分片段)),代表query和hit序列中有 意义比对的区域。HSP
对象包含在Hit
对象中,而且每个Hit
有一个 或更多的HSP
对象。HSPFragment
,代表query和hit序列中单个的邻近比对。HSPFragment
对象包含在HSP
对象中。多数的搜索工具如BLAST和HMMER把HSP
和HSPFragment
合并,因为一个HSP
只含有一个HSPFragment
。但是 像BLAT和Exonerate会产生含有多个HSPFragment
的HSP
。似乎有些困 惑?不要紧,稍后我们将详细介绍这两个对象。
这四个对象是当你用 Bio.SearchIO
会碰到的。 Bio.SearchIO
四
个主要方法: read
,parse
,index
或 index_db
中任意一个都可
以产生这四个对象。这些方法的会在后面的部分详细介绍。这部分只会用到 read
和
parse
,这两个方法和 Bio.SeqIO
以及 Bio.AlignIO
中的 read
和 parse
方法功
能相似:
read
用于单query对输出文件进行搜索并且返回一个QueryResult
对象。parse
用于多query对输出文件进行搜索并且返回一个可以yieldQueryResult
对象的generator。
完成这些之后,让我们开始学习每个 Bio.SearchIO
对象,从 QueryResult
开始。
8.1.1 QueryResult¶
QueryResult
,代表单query搜索,每个 QueryResult
中有0个或多个 Hit
对象。我们来看看BLAST文件是什么样的:
>>> from Bio import SearchIO
>>> blast_qresult = SearchIO.read('my_blast.xml', 'blast-xml')
>>> print blast_qresult
Program: blastn (2.2.27+)
Query: 42291 (61)
mystery_seq
Target: refseq_rna
Hits: ---- ----- ----------------------------------------------------------
# # HSP ID + description
---- ----- ----------------------------------------------------------
0 1 gi|262205317|ref|NR_030195.1| Homo sapiens microRNA 52...
1 1 gi|301171311|ref|NR_035856.1| Pan troglodytes microRNA...
2 1 gi|270133242|ref|NR_032573.1| Macaca mulatta microRNA ...
3 2 gi|301171322|ref|NR_035857.1| Pan troglodytes microRNA...
4 1 gi|301171267|ref|NR_035851.1| Pan troglodytes microRNA...
5 2 gi|262205330|ref|NR_030198.1| Homo sapiens microRNA 52...
6 1 gi|262205302|ref|NR_030191.1| Homo sapiens microRNA 51...
7 1 gi|301171259|ref|NR_035850.1| Pan troglodytes microRNA...
8 1 gi|262205451|ref|NR_030222.1| Homo sapiens microRNA 51...
9 2 gi|301171447|ref|NR_035871.1| Pan troglodytes microRNA...
10 1 gi|301171276|ref|NR_035852.1| Pan troglodytes microRNA...
11 1 gi|262205290|ref|NR_030188.1| Homo sapiens microRNA 51...
12 1 gi|301171354|ref|NR_035860.1| Pan troglodytes microRNA...
13 1 gi|262205281|ref|NR_030186.1| Homo sapiens microRNA 52...
14 2 gi|262205298|ref|NR_030190.1| Homo sapiens microRNA 52...
15 1 gi|301171394|ref|NR_035865.1| Pan troglodytes microRNA...
16 1 gi|262205429|ref|NR_030218.1| Homo sapiens microRNA 51...
17 1 gi|262205423|ref|NR_030217.1| Homo sapiens microRNA 52...
18 1 gi|301171401|ref|NR_035866.1| Pan troglodytes microRNA...
19 1 gi|270133247|ref|NR_032574.1| Macaca mulatta microRNA ...
20 1 gi|262205309|ref|NR_030193.1| Homo sapiens microRNA 52...
21 2 gi|270132717|ref|NR_032716.1| Macaca mulatta microRNA ...
22 2 gi|301171437|ref|NR_035870.1| Pan troglodytes microRNA...
23 2 gi|270133306|ref|NR_032587.1| Macaca mulatta microRNA ...
24 2 gi|301171428|ref|NR_035869.1| Pan troglodytes microRNA...
25 1 gi|301171211|ref|NR_035845.1| Pan troglodytes microRNA...
26 2 gi|301171153|ref|NR_035838.1| Pan troglodytes microRNA...
27 2 gi|301171146|ref|NR_035837.1| Pan troglodytes microRNA...
28 2 gi|270133254|ref|NR_032575.1| Macaca mulatta microRNA ...
29 2 gi|262205445|ref|NR_030221.1| Homo sapiens microRNA 51...
~~~
97 1 gi|356517317|ref|XM_003527287.1| PREDICTED: Glycine ma...
98 1 gi|297814701|ref|XM_002875188.1| Arabidopsis lyrata su...
99 1 gi|397513516|ref|XM_003827011.1| PREDICTED: Pan panisc...
虽然我们才接触对象模型的皮毛,但是你已经可以看到一些有用的信息了。通过调用``QueryResult`` 对象的 print
方法,你可以看到:
- 程序的名称和版本 (blastn version 2.2.27+)
- query的ID,描述和序列长度(ID是42291,描述是 ‘mystery_seq’,长度是61)
- 搜索的目标数据库 (refseq_rna)
- hit结果的快速预览。对于我们的查询序列,有100个可能的hit(表格中表示的是
0-99)对于每个hit,我们可以看到它包含的高分比对片段(HSP),ID和一个片
段描述。注意,
Bio.SearchIO
截断了表格,只显示0-29,然后是97-99。
现在让我们用同样的步骤来检查BLAT的结果:
>>> blat_qresult = SearchIO.read('my_blat.psl', 'blat-psl')
>>> print blat_qresult
Program: blat (<unknown version>)
Query: mystery_seq (61)
<unknown description>
Target: <unknown target>
Hits: ---- ----- ----------------------------------------------------------
# # HSP ID + description
---- ----- ----------------------------------------------------------
0 17 chr19 <unknown description>
马上可以看到一些不同点。有些是由于BLAT使用PSL格式储存它的信息,稍后会看 到。其余是由于BLAST和BLAT搜索的程序和数据库之间明显的差异造成的:
- 程序名称和版本。
Bio.SearchIO
知道程序是BLAST,但是在输出文件中没 有信息显示程序版本,所以默认是 ‘<unknown version>’。 - query的ID,描述和序列的长度。注意,这些细节和BLAST的细节只有细小的差别, ID是 ‘mystery_seq’ 而不是42991,缺少描述,但是序列长度仍是61。这 实际上是文件格式本身导致的差异。BLAST有时创建自己的query ID并且用你的原 始ID作为序列描述。
- 目标数据库是未知的,因为BLAT输出文件没提到相关信息。
- 最后,hit列表完全不同。这里,我们的查询序列只命中到 ‘chr19’ 数据库条 目,但是我们可以看到它含有17个HSP区域。这并不让人诧异,考虑到我们 使用的是不同的程序,并且这些程序都有自己的数据库。
所有通过调用 print
方法看到的信息都可以单独地用Python的对象属性获得(又叫点标记法)。同样还可以用相同的方法获得其他格式特有的属性。
>>> print "%s %s" % (blast_qresult.program, blast_qresult.version)
blastn 2.2.27+
>>> print "%s %s" % (blat_qresult.program, blat_qresult.version)
blat <unknown version>
>>> blast_qresult.param_evalue_threshold # blast-xml specific
10.0
想获得一个可访问属性的完整列表,可以查询每个格式特有的文档。这些是 BLAST BLAT.
已经知道了在 QueryResult
对象上可以调用 print
方法,让我们研究的更深
一些。 QueryResult
到底是什么?就Python对象来说, QueryResult
混合
了列表和字典的特性。换句话说,也就是一个包含了列表和字典功能的容器对象。
和列表以及字典一样, QueryResult
对象是可迭代的。每次迭代返回一个hit
对象:
>>> for hit in blast_qresult:
... hit
Hit(id='gi|262205317|ref|NR_030195.1|', query_id='42291', 1 hsps)
Hit(id='gi|301171311|ref|NR_035856.1|', query_id='42291', 1 hsps)
Hit(id='gi|270133242|ref|NR_032573.1|', query_id='42291', 1 hsps)
Hit(id='gi|301171322|ref|NR_035857.1|', query_id='42291', 2 hsps)
Hit(id='gi|301171267|ref|NR_035851.1|', query_id='42291', 1 hsps)
...
要得到 QueryResult
对象有多少hit,可以简单调用Python的 len
方法:
>>> len(blast_qresult)
100
>>> len(blat_qresult)
1
同列表类似,你可以用切片来获得 QueryResult
对象的hit:
>>> blast_qresult[0] # retrieves the top hit
Hit(id='gi|262205317|ref|NR_030195.1|', query_id='42291', 1 hsps)
>>> blast_qresult[-1] # retrieves the last hit
Hit(id='gi|397513516|ref|XM_003827011.1|', query_id='42291', 1 hsps)
要得到多个hit,你同样可以对 QueryResult
对象作切片。这种情况下,返回一个包含被切hit的新 QueryResult
对象:
>>> blast_slice = blast_qresult[:3] # slices the first three hits
>>> print blast_slice
Program: blastn (2.2.27+)
Query: 42291 (61)
mystery_seq
Target: refseq_rna
Hits: ---- ----- ----------------------------------------------------------
# # HSP ID + description
---- ----- ----------------------------------------------------------
0 1 gi|262205317|ref|NR_030195.1| Homo sapiens microRNA 52...
1 1 gi|301171311|ref|NR_035856.1| Pan troglodytes microRNA...
2 1 gi|270133242|ref|NR_032573.1| Macaca mulatta microRNA ...
同字典类似,可以通过ID获取hit。如果你知道一个特定的hit ID存在于一个搜索结果中时,特别有用:
>>> blast_qresult['gi|262205317|ref|NR_030195.1|']
Hit(id='gi|262205317|ref|NR_030195.1|', query_id='42291', 1 hsps)
你可以用 hits
方法获得完整的 Hit
对象,也可以用 hit_keys
方法获得完整的 Hit
ID:
>>> blast_qresult.hits
[...] # list of all hits
>>> blast_qresult.hit_keys
[...] # list of all hit IDs
如果你想确定一个特定的hit是否存在于查询结果中该怎么做呢?可以用 in
关键字作一个简单的成员检验:
>>> 'gi|262205317|ref|NR_030195.1|' in blast_qresult
True
>>> 'gi|262205317|ref|NR_030194.1|' in blast_qresult
False
有时候,只知道一个hit是否存在是不够的,你可能也会想知道hit的排名。 index
方法可以帮助你:
>>> blast_qresult.index('gi|301171437|ref|NR_035870.1|')
22
记住,我们用的是Python风格的索引,是从0开始。这代表hit的排名是23而不是22。
同样,注意你看的hit排名是基于原始搜索输出文件的本来顺序。不同的搜索工具可 能会基于不同的标准排列hit。
如果原本的hit排序不合你意,可以用 QueryResult
对象的 sort
方法。
它和Python的 list.sort
方法很相似,只是有个是否创建一个新的排序后的
QueryResult
对象的选项。
这里有个用 QueryResult.sort
方法对hit排序的例子,这个方法基于每个hit
的完整序列长度。对于这个特殊的排序,我们设置 in_place
参数等于 False
,
这样排序方法会返回一个新的 QueryResult
对象,而原来的对象是未排序的。
我们同样可以设置 reverse
参数等于 `` True `` 以递减排序。
>>> for hit in blast_qresult[:5]: # id and sequence length of the first five hits
... print hit.id, hit.seq_len
...
gi|262205317|ref|NR_030195.1| 61
gi|301171311|ref|NR_035856.1| 60
gi|270133242|ref|NR_032573.1| 85
gi|301171322|ref|NR_035857.1| 86
gi|301171267|ref|NR_035851.1| 80
>>> sort_key = lambda hit: hit.seq_len
>>> sorted_qresult = blast_qresult.sort(key=sort_key, reverse=True, in_place=False)
>>> for hit in sorted_qresult[:5]:
... print hit.id, hit.seq_len
...
gi|397513516|ref|XM_003827011.1| 6002
gi|390332045|ref|XM_776818.2| 4082
gi|390332043|ref|XM_003723358.1| 4079
gi|356517317|ref|XM_003527287.1| 3251
gi|356543101|ref|XM_003539954.1| 2936
有 in_place
参数的好处是可以保留原本的顺序,后面会用到。注意这不是 QueryResult.sort
的默认行为,需要我们明确地设置 in_place
为 True
。
现在,你已经知道使用 QueryResult
对象。但是,在我们学习 Bio.SearchIO
模块下个对象前,先了解下可以让 QueryResult
对象更易使用的两个方法:
filter
和 map
方法。
如果你对Python的列表推导式、generator表达式或内建的 filter
和 map
很熟悉,就知道(不知道就是看看吧!)它们在处理list-like的对象时有多有用。
你可以用这些内建的方法来操作 QueryResult
对象,但是这只对正常list有效,并且可操作性也会受到限制。
这就是为什么 QueryResult
对象提供自己特有的 filter
和 map
方法。对于 filter
有相似的 hit_filter
和 hsp_filter
方法,
从名称就可以看出,这些方法过滤 QueryResult
对象的 Hit
对象或者
HSP
对象。同样的,对于 map
, QueryResult
对象同样提供相似
的 hit_map
和 hsp_map
方法。这些方法分别应用于 QueryResult
对象 hit
或者 HSP
对象。
让我们来看看这些方法的功能,从 hit_filter
开始。这个方法接受一个回调
函数,这个函数检验给定的 Hit
是否符合你设定的条件。换句话说,这个方法
必须接受一个单独 Hit
对象作为参数并且返回 True
或 False
。
这里有个用 hit_filter
筛选出只有一个HSP的 Hit
对象的例子:
>>> filter_func = lambda hit: len(hit.hsps) > 1 # the callback function
>>> len(blast_qresult) # no. of hits before filtering
100
>>> filtered_qresult = blast_qresult.hit_filter(filter_func)
>>> len(filtered_qresult) # no. of hits after filtering
37
>>> for hit in filtered_qresult[:5]: # quick check for the hit lengths
... print hit.id, len(hit.hsps)
gi|301171322|ref|NR_035857.1| 2
gi|262205330|ref|NR_030198.1| 2
gi|301171447|ref|NR_035871.1| 2
gi|262205298|ref|NR_030190.1| 2
gi|270132717|ref|NR_032716.1| 2
hsp_filter
和 hit_filter
功能相同,只是它过滤每个hit中的 HSP
对象,
而不是 Hit
。
对于 map
方法,同样接受一个回调函数作为参数。但是回调函数返回修改过的 Hit
或 HSP
对象(取决于你是否使用 hit_map
或 hsp_map
方法),
而不是返回 True
或 False
。
来看一个用 hit_map
方法来重命名hit ID的例子:
>>> def map_func(hit):
... hit.id = hit.id.split('|')[3] # renames 'gi|301171322|ref|NR_035857.1|' to 'NR_035857.1'
... return hit
...
>>> mapped_qresult = blast_qresult.hit_map(map_func)
>>> for hit in mapped_qresult[:5]:
... print hit.id
NR_030195.1
NR_035856.1
NR_032573.1
NR_035857.1
NR_035851.1
同样的, hsp_map
和 hit_map
作用相似, 但是作用于 HSP
对象而不是 Hit
对象。
8.1.2 Hit¶
Hit
对象代表从单个数据库获得所有查询结果。在 Bio.SearchIO
对象等级中是二级容器。它们被包含在 QueryResult
对象中,同时它们又包含 HSP
对象。
看看它们是什么样的,从我们的BLAST搜索开始:
>>> from Bio import SearchIO
>>> blast_qresult = SearchIO.read('my_blast.xml', 'blast-xml')
>>> blast_hit = blast_qresult[3] # fourth hit from the query result
>>> print blast_hit
Query: 42291
mystery_seq
Hit: gi|301171322|ref|NR_035857.1| (86)
Pan troglodytes microRNA mir-520c (MIR520C), microRNA
HSPs: ---- -------- --------- ------ --------------- ---------------------
# E-value Bit score Span Query range Hit range
---- -------- --------- ------ --------------- ---------------------
0 8.9e-20 100.47 60 [1:61] [13:73]
1 3.3e-06 55.39 60 [0:60] [13:73]
可以看到我们获得了必要的信息:
- query的ID和描述信息。一个hit总是和一个query绑定,所以我们同样希望记录原始
query。这些值可以通过
query_id
和query_description
属性从hit 中获取。 - 我们同样得到了hit的ID、描述和序列全长。它们可以分别通过
id
,description
,和seq_len
获取。 - 最后,有一个hit含有的HSP的简短信息表。在每行中,HSP重要信息被 列出来:HSP索引,e值,得分,长度(包括gap),query坐标和hit坐标。
现在,和BLAT结果作对比。记住,在BLAT搜索结果中,我们发现有一个含有17HSP的hit。
>>> blat_qresult = SearchIO.read('my_blat.psl', 'blat-psl')
>>> blat_hit = blat_qresult[0] # the only hit
>>> print blat_hit
Query: mystery_seq
<unknown description>
Hit: chr19 (59128983)
<unknown description>
HSPs: ---- -------- --------- ------ --------------- ---------------------
# E-value Bit score Span Query range Hit range
---- -------- --------- ------ --------------- ---------------------
0 ? ? ? [0:61] [54204480:54204541]
1 ? ? ? [0:61] [54233104:54264463]
2 ? ? ? [0:61] [54254477:54260071]
3 ? ? ? [1:61] [54210720:54210780]
4 ? ? ? [0:60] [54198476:54198536]
5 ? ? ? [0:61] [54265610:54265671]
6 ? ? ? [0:61] [54238143:54240175]
7 ? ? ? [0:60] [54189735:54189795]
8 ? ? ? [0:61] [54185425:54185486]
9 ? ? ? [0:60] [54197657:54197717]
10 ? ? ? [0:61] [54255662:54255723]
11 ? ? ? [0:61] [54201651:54201712]
12 ? ? ? [8:60] [54206009:54206061]
13 ? ? ? [10:61] [54178987:54179038]
14 ? ? ? [8:61] [54212018:54212071]
15 ? ? ? [8:51] [54234278:54234321]
16 ? ? ? [8:61] [54238143:54238196]
我们得到了和前面看到的BLAST hit详细程度相似的结果。但是有些不同点需要解释:
- e-value和bit score列的值。因为BLAT HSP没有e-values和bit scores,默 认显示‘?’.
- span列是怎么回事呢?span值本来是显示完整的比对长度,包含所有的残基和
gap。但是PSL格式目前还不支持这些信息并且
Bio.SearchIO
也不打算去猜它到底是多少,所有我们得到了和e-value以及bit score列相同的 ‘?’。
就Python对象来说, Hit
和列表行为最相似,但是额外含有 HSP
。如果
你对列表熟悉,在使用 Hit
对象是不会遇到困难。
和列表一样, Hit
对象是可迭代的,并且每次迭代返回一个 HSP
对象:
>>> for hsp in blast_hit:
... hsp
HSP(hit_id='gi|301171322|ref|NR_035857.1|', query_id='42291', 1 fragments)
HSP(hit_id='gi|301171322|ref|NR_035857.1|', query_id='42291', 1 fragments)
你可以对 Hit
对象调用 len
方法查看它含有多少个 HSP
对象:
>>> len(blast_hit)
2
>>> len(blat_hit)
17
你可以对 Hit
对象作切片取得单个或多个 HSP
对象,和 QueryResult
一样,如果切取多个 HSP
,会返回包含被切片 HSP
的一个新 Hit
对象。
>>> blat_hit[0] # retrieve single items
HSP(hit_id='chr19', query_id='mystery_seq', 1 fragments)
>>> sliced_hit = blat_hit[4:9] # retrieve multiple items
>>> len(sliced_hit)
5
>>> print sliced_hit
Query: mystery_seq
<unknown description>
Hit: chr19 (59128983)
<unknown description>
HSPs: ---- -------- --------- ------ --------------- ---------------------
# E-value Bit score Span Query range Hit range
---- -------- --------- ------ --------------- ---------------------
0 ? ? ? [0:60] [54198476:54198536]
1 ? ? ? [0:61] [54265610:54265671]
2 ? ? ? [0:61] [54238143:54240175]
3 ? ? ? [0:60] [54189735:54189795]
4 ? ? ? [0:61] [54185425:54185486]
你同样可以对一个 Hit
里的 HSP
排序,和你在 QueryResult
对象
中看到的方法一样。
最后,同样可以对 Hit
对象使用 filter
和 map
方法。和 QueryResult
不同, Hit
对象只有一种 filter
(Hit.filter
) 和一种 map
(Hit.map
)。
8.1.3 HSP¶
HSP
(高分片段)代表hit序列中的一个区域,该区域包含对于查询序列有意义的
比对。它包含了你的查询序列和一个数据库条目之间精确的匹配。由于匹配取决于
序列搜索工具的算法, HSP
含有大部分统计信息,这些统计是由搜索工具计
算得到的。这使得不同搜索工具的 HSP
对象之间的差异和你在 QueryResult
以及 Hit
对象看到的差异更加明显。
我们来看看BLAST和BLAT搜索的例子。先看BLAST HSP:
>>> from Bio import SearchIO
>>> blast_qresult = SearchIO.read('my_blast.xml', 'blast-xml')
>>> blast_hsp = blast_qresult[0][0] # first hit, first hsp
>>> print blast_hsp
Query: 42291 mystery_seq
Hit: gi|262205317|ref|NR_030195.1| Homo sapiens microRNA 520b (MIR520...
Query range: [0:61] (1)
Hit range: [0:61] (1)
Quick stats: evalue 4.9e-23; bitscore 111.29
Fragments: 1 (61 columns)
Query - CCCTCTACAGGGAAGCGCTTTCTGTTGTCTGAAAGAAAAGAAAGTGCTTCCTTTTAGAGGG
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Hit - CCCTCTACAGGGAAGCGCTTTCTGTTGTCTGAAAGAAAAGAAAGTGCTTCCTTTTAGAGGG
和 QueryResult
以及 Hit
类似,调用 HSP
的 print
方法,
显示细节:
- 有query和hit的ID以及描述。我们需要这些来识别我们的
HSP
。 - 我们同样得到了query和hit序列的匹配范围。这里用的的切片标志着范围的表示 是使用Python的索引风格(从0开始,半开区间)。圆括号里的数字表示正负链。 这里,两条序列都是正链。
- 还有一些简短统计:e-value和bitscore。
- 还有一些HSP片段的信息。现在可以忽略,稍后会解释。
- 最后,还有query和hit的比对。
这些信息可以用点标记从它们本身获得,和 Hit
以及 QueryResult
相同:
>>> blast_hsp.query_range
(0, 61)
>>> blast_hsp.evalue
4.91307e-23
它们并不是仅有的属性, HSP
对象有一系列的属性,使得获得它们的具体信
息更加容易。下面是一些例子:
>>> blast_hsp.hit_start # start coordinate of the hit sequence
0
>>> blast_hsp.query_span # how many residues in the query sequence
61
>>> blast_hsp.aln_span # how long the alignment is
61
查看 HSP
文档
获取完整的属性列表。
不仅如此,每个搜索工具通常会对它的 HSP
对象作统计学或其他细节计算。例如,一个
XML BLAST搜索同样输出gap以及相同的残基数量。这些属性可以像这样被获取:
>>> blast_hsp.gap_num # number of gaps
0
>>> blast_hsp.ident_num # number of identical residues
61
这些细节是格式特异的;它们可能不会出现在其他的格式中。要知道哪些细节在给
定的序列搜索工具中是存在的,你应该查看那种格式的在 Bio.SearchIO
中的
文档。或者可以用 .__dict__.keys()
获得快速列表:
>>> blast_hsp.__dict__.keys()
['bitscore', 'evalue', 'ident_num', 'gap_num', 'bitscore_raw', 'pos_num', '_items']
最后,你可能已经注意到了,我们HSP的 query
和 hit
属性不只是规律字符串:
>>> blast_hsp.query
SeqRecord(seq=Seq('CCCTCTACAGGGAAGCGCTTTCTGTTGTCTGAAAGAAAAGAAAGTGCTTCCTTT...GGG', DNAAlphabet()), id='42291', name='aligned query sequence', description='mystery_seq', dbxrefs=[])
>>> blast_hsp.hit
SeqRecord(seq=Seq('CCCTCTACAGGGAAGCGCTTTCTGTTGTCTGAAAGAAAAGAAAGTGCTTCCTTT...GGG', DNAAlphabet()), id='gi|262205317|ref|NR_030195.1|', name='aligned hit sequence', description='Homo sapiens microRNA 520b (MIR520B), microRNA', dbxrefs=[])
它们是你已经在第 4 章看到过的 SeqRecord
对象!
意味着你可以对 SeqRecord
对象做的各种有趣的事同样适用于 HSP.query
和 HSP.hit
对象。
现在 HSP
对象有个 alignment
属性(一个 MultipleSeqAlignment
对象)应该不会让你感到惊讶:
>>> print blast_hsp.aln
DNAAlphabet() alignment with 2 rows and 61 columns
CCCTCTACAGGGAAGCGCTTTCTGTTGTCTGAAAGAAAAGAAAG...GGG 42291
CCCTCTACAGGGAAGCGCTTTCTGTTGTCTGAAAGAAAAGAAAG...GGG gi|262205317|ref|NR_030195.1|
探索完BLAST HSP对象,让我们看看来自BLAT结果的不一样的HSP。我们将对它调用 print
方法:
>>> blat_qresult = SearchIO.read('my_blat.psl', 'blat-psl')
>>> blat_hsp = blat_qresult[0][0] # first hit, first hsp
>>> print blat_hsp
Query: mystery_seq <unknown description>
Hit: chr19 <unknown description>
Query range: [0:61] (1)
Hit range: [54204480:54204541] (1)
Quick stats: evalue ?; bitscore ?
Fragments: 1 (? columns)
一些输出你应该已经猜到了。我们得到了查询序列、hit ID、描述以及序列坐标。
evalue和bitscore的值是 ‘?’ ,因为BLAT HSP并没有这些属性。但是最大的不同
是你看不到任何的序列比对展示。如果你看的更仔细,PSL格式本身并没有任何的
hit和query序列,所以 Bio.SearchIO
不会创建任何序列或者比对对象。如果
你尝试获取 HSP.query
,HSP.hit
, 或者 HSP.aln
属性会怎么样
呢?你会得到这些属性的默认值 None
:
>>> blat_hsp.hit is None
True
>>> blat_hsp.query is None
True
>>> blat_hsp.aln is None
True
这并不影响其他的属性。例如,你仍然可以获取query和hit比对的长度。尽管不显
示任何的属性,但是PSL格式还是有这些信息的,所以 Bio.SearchIO
可以抽
提出这些信息。
>>> blat_hsp.query_span # length of query match
61
>>> blat_hsp.hit_span # length of hit match
61
其他格式特异的属性同样被展示出来:
>>> blat_hsp.score # PSL score
61
>>> blat_hsp.mismatch_num # the mismatch column
0
到目前为止,一切还不错?当你看到BLAT结果中不同的HSP时,事情变得更有趣了。 你可能会回想起在BLAT搜索中,有时我们把结果分成 ‘blocks’ 。这些区块是必需比对片段,可能会有些内含子在它们之间。
让我们看看 Bio.SearchIO
怎么处理包含多个区块的BLAT HSP:
>>> blat_hsp2 = blat_qresult[0][1] # first hit, second hsp
>>> print blat_hsp2
Query: mystery_seq <unknown description>
Hit: chr19 <unknown description>
Query range: [0:61] (1)
Hit range: [54233104:54264463] (1)
Quick stats: evalue ?; bitscore ?
Fragments: --- -------------- ---------------------- ----------------------
# Span Query range Hit range
--- -------------- ---------------------- ----------------------
0 ? [0:18] [54233104:54233122]
1 ? [18:61] [54264420:54264463]
怎么回事?我们仍然得到了一些必要的信息:ID,描述信息,坐标和快速统计,和 你前面看到的一样。但是片段信息完全不同。我们得到了有两行数据的表格,而不是显示 ‘Fragment: 1’。
这就是 Bio.SearchIO
处理含有多片段HSP的方式。和前面提到的一样,一个
HSP比对可能会被内含子分成多个片段。内含子不是query-hit匹配的一部分,所以
它们不能被当成query或hit序列的一部分。但是,它们确实影响我们处理序列坐标,
所以我们不能忽视。
看看上面的HSP的hit坐标。在 Hit range
区域,我们看到坐标是
[54233104:54264463]
。但是看看表格中的行,我们发现不是坐标跨度的所有区域
都能匹配我们的query。特殊的是,间断区域从 54233122
到 54264420
。
你可能会问,为什么query坐标好像是邻近的?这是很好的。在这个例子中,query是连续的(无间断区域),但是hit却不是。
所有的这些属性都是可以直接从HSP获取的,通过这样的方式:
>>> blat_hsp2.hit_range # hit start and end coordinates of the entire HSP
(54233104, 54264463)
>>> blat_hsp2.hit_range_all # hit start and end coordinates of each fragment
[(54233104, 54233122), (54264420, 54264463)]
>>> blat_hsp2.hit_span # hit span of the entire HSP
31359
>>> blat_hsp2.hit_span_all # hit span of each fragment
[18, 43]
>>> blat_hsp2.hit_inter_ranges # start and end coordinates of intervening regions in the hit sequence
[(54233122, 54264420)]
>>> blat_hsp2.hit_inter_spans # span of intervening regions in the hit sequence
[31298]
这些属性中大多数都不能简单地从PSL文件获得,但是当你分析PSL文件时,
Bio.SearchIO
会动态地帮你计算。它需要的只是每个片段的开始和结束坐标。
query
, hit
, 和 aln
属性又是什么情况?如果HSP含有多个片段,
你就不能使用这些属性,因为它们只取回单个 SeqRecord
或
MultipleSeqAlignment
对象。但是,你可以用相应的 *_all
方法:
query_all
, hit_all
, 和 aln_all
。 这些属性会返回包含每个HSP
片段的 SeqRecord
或 MultipleSeqAlignment
对象的列表。还有其他相同
功能的属性,也就是只对只有一个片段的HSP有效。查看 HSP
文档
获得完整的列表。
最后,想要检查是否是多片段HSP,你可以用 is_fragmented
属性:
>>> blat_hsp2.is_fragmented # BLAT HSP with 2 fragments
True
>>> blat_hsp.is_fragmented # BLAT HSP from earlier, with one fragment
False
在进入下部分之前,你只需要了解我们可以对 HSP
对象使用切片,和
QueryResult
或 Hit
对象一样。当你使用切片的时候,会返回一个
HSPFragment
对象。
8.1.4 HSP片段¶
HSPFragment
代表query和hit之间单个连续匹配。应该把它当作对象模型
和搜索结果的核心,因为它决定你的搜索是否有结果。
在多数情况下,你不必直接处理 HSPFragment
对象,因为没有那么多搜索工具
断裂它们的HSP。当你确实需要处理它们时,需要记住的是 HSPFragment
对象
要被写地尽量压缩。在多数情况下,它们仅仅包含直接与序列有关的属性:正负链,
阅读框,字母表,位置坐标,序列本身以及它们的ID和描述。
当你对 HSPFragment
对象调用 print
方法时,这些属性可以非常简单地显示
出来。这里有个从我们BLAST搜索得到的例子:
>>> from Bio import SearchIO
>>> blast_qresult = SearchIO.read('my_blast.xml', 'blast-xml')
>>> blast_frag = blast_qresult[0][0][0] # first hit, first hsp, first fragment
>>> print blast_frag
Query: 42291 mystery_seq
Hit: gi|262205317|ref|NR_030195.1| Homo sapiens microRNA 520b (MIR520...
Query range: [0:61] (1)
Hit range: [0:61] (1)
Fragments: 1 (61 columns)
Query - CCCTCTACAGGGAAGCGCTTTCTGTTGTCTGAAAGAAAAGAAAGTGCTTCCTTTTAGAGGG
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Hit - CCCTCTACAGGGAAGCGCTTTCTGTTGTCTGAAAGAAAAGAAAGTGCTTCCTTTTAGAGGG
在这个水平上,BLAT和BLAST片段看起来非常相似,除了没有出现的query和hit序列:
>>> blat_qresult = SearchIO.read('my_blat.psl', 'blat-psl')
>>> blat_frag = blat_qresult[0][0][0] # first hit, first hsp, first fragment
>>> print blat_frag
Query: mystery_seq <unknown description>
Hit: chr19 <unknown description>
Query range: [0:61] (1)
Hit range: [54204480:54204541] (1)
Fragments: 1 (? columns)
在所有情况下,这些属性都可以通过我们最爱的点标记访问。一些例子:
>>> blast_frag.query_start # query start coordinate
0
>>> blast_frag.hit_strand # hit sequence strand
1
>>> blast_frag.hit # hit sequence, as a SeqRecord object
SeqRecord(seq=Seq('CCCTCTACAGGGAAGCGCTTTCTGTTGTCTGAAAGAAAAGAAAGTGCTTCCTTT...GGG', DNAAlphabet()), id='gi|262205317|ref|NR_030195.1|', name='aligned hit sequence', description='Homo sapiens microRNA 520b (MIR520B), microRNA', dbxrefs=[])
8.2 一个关于标准和惯例的注意事项¶
在我们进入到主要功能前,你需要知道 Bio.SearchIO
使用的一些标准。如果
你已经接触过多序列搜索工具,你可能必须面对每个程序处理事情方式不同的问题,
如序列位置坐标。这可能不是一个令人高兴的经历,因为这些搜索工具通常有它们
自己的标准。例如,一种工具可能使用“从1开始”(one-based)的坐标,而其他工具
使用“从0开始”(zero-based)的坐标。或者,一种程序在处理负链时,可能会反转
开始和结束坐标,而其他程序确不会。简而言之,会产生一些必须要处理的混乱。
我们意识到这种问题,并且打算在 Bio.SearchIO
中解决。毕竟, Bio.SearchIO
的目标之一就是创建一个通用简单的接口来处理多种不同的搜索
输出文件。意味着要制定一个超越你所见的对象模型的标准。
现在,你可能抱怨,”不要又来一个标准“。好吧,最后我们必须选择一个标准,这 是必须的。并且,我们并不是创造一个全新的事物;只是采用一个我们觉得对Python 使用者最好的标准(这是Biopython,毕竟)。
在使用 Bio.SearchIO
时你可以认为有个三个隐含的标准:
- 第一个适用于序列坐标。在
Bio.SearchIO
模块中,所有序列坐标遵循Python 的坐标风格: 从0开始,半开区间。例如,在一个BLAST XML输出文件中,HSP的起始和结束坐标 是10和28,它们在Bio.SearchIO
中将变成9和28。起始坐标变成9因为Python 中索引是从0开始,而结束坐标仍然是28因为Python索引删除了区间中最后一个 项目。 - 第二个是关于序列坐标顺序。在
Bio.SearchIO
中,开始坐标总是小于或 等于结束坐标。但是这不是在所有的序列搜索工具中都始终适用。因为当序列 为负链时,起始坐标会更大一些。 - 最后一个标准是关于链和阅读框的值。对于链值,只有四个可选值:
1
(正链),-1
(负链),0
(蛋白序列), 和None
(无链)。对于阅读框, 可选值是从-3
至3
的整型以及None
。
注意,这些标准只是存在于 Bio.SearchIO
对象中。如果你把 Bio.SearchIO
对象写入一种输出格式, Bio.SearchIO
会使用该格式的标准来输出。它并不
强加它的标准到你的输出文件。
8.3 读取搜索输出文件¶
有两个方法,你可以用来读取搜索输出文件到 Bio.SearchIO
对象: read
和 parse
。
它们和其他亚模块如 Bio.SeqIO
或 Bio.AlignIO
中的 read
和 parse
方法在
本质上是相似的。你都需要提供搜索输出文件名和文件格式名,都是Python字符串类型。你可以
查阅文档来获得 Bio.SearchIO
可以识别的格式清单。
Bio.SearchIO.read
用于读取单query的搜索输出文件并且返回一个 QueryResult
对象。你在前面的例子中已经看到过 read
的使用了。
你没看到的是, read
同样接受额外的关键字参数,取决于文件的格式。
这里有一些例子。在第一个例子中,我们和前面一样用 read
读BLAST表格输出
文件。在第二个例子中,我们用一个关键字来修饰,所以它分析带有注释的BLAST
表格变量。
>>> from Bio import SearchIO
>>> qresult = SearchIO.read('tab_2226_tblastn_003.txt', 'blast-tab')
>>> qresult
QueryResult(id='gi|16080617|ref|NP_391444.1|', 3 hits)
>>> qresult2 = SearchIO.read('tab_2226_tblastn_007.txt', 'blast-tab', comments=True)
>>> qresult2
QueryResult(id='gi|16080617|ref|NP_391444.1|', 3 hits)
这些关键字在不同的文件格式中是不一样的。查看格式文档,看看它是否有关键字参数来控制它的分析器行为。
对于 Bio.SearchIO.parse
,是用来读取含有任意数量query的搜索输出文件。
这个方法返回一个generator对象,在每次迭代中yield一个 QueryResult
对象。
和 Bio.SearchIO.read
一样,它同样接受格式特异的关键字参数:
>>> from Bio import SearchIO
>>> qresults = SearchIO.parse('tab_2226_tblastn_001.txt', 'blast-tab')
>>> for qresult in qresults:
... print qresult.id
gi|16080617|ref|NP_391444.1|
gi|11464971:4-101
>>> qresults2 = SearchIO.parse('tab_2226_tblastn_005.txt', 'blast-tab', comments=True)
>>> for qresult in qresults2:
... print qresult.id
random_s00
gi|16080617|ref|NP_391444.1|
gi|11464971:4-101
8.4 用索引处理含有大量搜索输出的文件¶
有时,你得到了一个包含成百上千个query的搜索输出文件要分析,你当然可以使用
Bio.SearchIO.parse
来处理,但是如果你仅仅需要访问少数query的话,效率
是及其低下的。这是因为 parse
会分析所有的query,直到找到你感兴趣。
在这种情况下,理想的选择是用 Bio.SearchIO.index
或 Bio.SearchIO.index_db
来索引文件。如果名字听起来很熟悉,是因为你之前已经见过了,在
章节 5.4.2 。这些方法和 Bio.SeqIO
中相应的方法行为很相似,只是多了些格式特异的关键字参数。
这里有一些例子。你可以只用文件名和格式名来 index
>>> from Bio import SearchIO
>>> idx = SearchIO.index('tab_2226_tblastn_001.txt', 'blast-tab')
>>> sorted(idx.keys())
['gi|11464971:4-101', 'gi|16080617|ref|NP_391444.1|']
>>> idx['gi|16080617|ref|NP_391444.1|']
QueryResult(id='gi|16080617|ref|NP_391444.1|', 3 hits)
或者依旧使用格式特异的关键字参数:
>>> idx = SearchIO.index('tab_2226_tblastn_005.txt', 'blast-tab', comments=True)
>>> sorted(idx.keys())
['gi|11464971:4-101', 'gi|16080617|ref|NP_391444.1|', 'random_s00']
>>> idx['gi|16080617|ref|NP_391444.1|']
QueryResult(id='gi|16080617|ref|NP_391444.1|', 3 hits)
或者使用 key_function
参数,和 Bio.SeqIO
中一样:
>>> key_function = lambda id: id.upper() # capitalizes the keys
>>> idx = SearchIO.index('tab_2226_tblastn_001.txt', 'blast-tab', key_function=key_function)
>>> sorted(idx.keys())
['GI|11464971:4-101', 'GI|16080617|REF|NP_391444.1|']
>>> idx['GI|16080617|REF|NP_391444.1|']
QueryResult(id='gi|16080617|ref|NP_391444.1|', 3 hits)
Bio.SearchIO.index_db
和 index
作用差不多,不同的只是它把query
偏移量写入一个SQLite数据库文件中。
8.5 写入和转换搜索输出文件¶
有时候,读取一个搜索输出文件,作些调整并写到一个新的文件是很有用的。
Bio.SearchIO
提供了一个 write
方法,让你可以准确地完成这种工作。
它需要的参数是:一个可迭代返回 QueryResult
的对象,输出文件名,输出文件
格式和一些可选的格式特异的关键字参数。它返回一个4项目的元组,分别代表
被写入的 QueryResult
, Hit
, HSP
, 和 HSPFragment
对象的数量。
>>> from Bio import SearchIO
>>> qresults = SearchIO.parse('mirna.xml', 'blast-xml') # read XML file
>>> SearchIO.write(qresults, 'results.tab', 'blast-tab') # write to tabular file
(3, 239, 277, 277)
你应该注意,不同的文件格式需要 QueryResult
, Hit
, HSP
和
HSPFragment
对象的不同属性。如果这些属性不存在,那么将不能写入。
也就是,你想写入的格式可能有时也会失效。举个例子,如果你读取一个BLASTXML文件,
你就不能将结果写入PSL文件,因为PSL文件需要一些属性,而这些属性BLAST却不能
提供(如重复匹配的数量)。如果你确实想写到PSL,可以手工设置这些属性。
和 read
, parse
, index
和 index_db
相似, write
同
样接受格式特异的关键字参数。查阅文档获得 Bio.SearchIO
可写格式和这些
格式的参数的完整清单。
最后, Bio.SearchIO
同样提供一个 convert
方法,可以理解为 Bio.SearchIO.parse
和 Bio.SearchIO.write
的简单替代方法。使用 convert
方法的例子如下:
>>> from Bio import SearchIO
>>> SearchIO.convert('mirna.xml', 'blast-xml', 'results.tab', 'blast-tab')
(3, 239, 277, 277)
因为 convert
使用 write
方法,所以只有所有需要的属性都存在时,格式
转换才能正常工作。这里由于BLAST XML文件提供BLAST 表格文件所需的所有默认值,
格式转换才能正常完成。但是,其他格式转换就可能不会正常工作,因为你需要先手工指定所需的属性。