我使用python/pysam来分析测序数据。在它的教程(pysam-一个读取和写入SAM文件的界面)中,它说:
"这种方法对于高通量处理来说太慢了。如果读取需要与其配偶一起处理,可以从读取名称排序的文件中处理,或者更好的是缓存读取。"
您将如何"缓存读取"?
缓存是加快长时间运行操作的典型方法。为了计算速度,它牺牲了内存。
假设您有一个函数,给定一组参数后,它总是返回相同的结果。不幸的是,这个函数非常慢,你需要调用它相当长的时间来减慢你的程序。
您可以做的是存储有限数量的{parameters:result}组合,并在使用相同参数调用函数时跳过其逻辑。
这是一个肮脏的技巧,但非常有效,尤其是当参数组合与函数速度相比较低时。
在Python3中有一个用于此目的的装饰器
在Python 2中,一个库可能会有所帮助,但您需要做更多的工作。
filepath_or_object
因此,您可以提供一个支持类文件接口的对象,即方法seek
、read
、tell
,而不是提供文件名。当为此实现一个类时,您还可以在读取上实现缓存,当然这必须取决于当前光标的位置。
如果文件大小足够小,可以放入内存,则可以读取完整的文件并对io.BytesIO
对象进行操作,而无需创建自己的类:
data = io.BytesIO(open('datafile','rb').read())
your_object = AlignmentFile(data, <other args>)
我不确定这是否会加快速度,因为我认为现代操作系统(我知道linux会这样做)可以访问缓存文件。所以,也许依靠这一点就足够了。
我发现其他答案并没有说明如何在实践中实际缓存读取。
这里有一个简单的方法:
from collections import defaultdict
from pysam import AlignmentFile
def get_mate(read_pairs, read):
if read.qname not in read_pairs or not (read.is_read1 ^ read.is_read2):
return None
pos = 1 if read.is_read1 else 0
return read_pairs[read.qname][pos]
# maps QNAME to a read pair
read_pairs = defaultdict(lambda : [None, None])
fin = AlignmentFile("your_filepath")
for read in fin.fetch(your_chrom,your_start,your_stop):
if read.is_paired and (read.is_read1 ^ read.is_read2):
pos = 0 if read.is_read1 else 1
read_pairs[read.qname][pos] = read
## Now compare execution time of these two commands
your_read_mate = fin.mate(your_read) # pysam, non-cached
your_read_mate = get_mate(read_pairs, your_read) # cached
其中读对的操作定义是(c.f.SAM格式):
- 两个读取具有相同的QNAME
- 每次读取都设置了标志0x1(
read.is_paired
) - 每次读取只设置了标志0x40(
read.is_read1
)或0x80(read.is_read2
)中的一个(XORread.is_read1 ^ read.is_read2
对此进行检查)
在我的机器上,使用ipython的%timeit
命令,对于给定的读取(我知道这对在read_pairs
中),我得到非缓存调用的18.9 ms ± 510 µs
和缓存调用的854 ns ± 28.7 ns
:-)