用于大字符串的Python缓冲区 - 更好还是更差?

时间:2015-03-04 21:55:01

标签: python string optimization buffer

我正在使用python来获取一个非常大的字符串(DNA序列)并尝试从中创建一个后缀树。在编写嵌套对象很长一段时间后,我的程序出现了内存错误,所以我认为为了提高性能,从字符串创建缓冲区而不是实际切片字符串可能很有用。两个版本都在下面,描述了相关问题。

第一个(非缓冲区)版本 - 处理大字符串大约一分钟后,currNode.out [substring [0]] = self发生 MemoryError 。节点(pos,substring [1:])

class SuffixTree(object):

class Node(object):
    def __init__(self, position, suffix):
        self.position = position
        self.suffix = suffix
        self.out = {}

def __init__(self, text):

    self.text = text
    self.max_repeat = 2
    self.repeats = {}
    self.root = self.Node(None, '')
    L = len(self.text)

    for i in xrange(L):

        substring = self.text[-1*(i+1):] + "$"
        currNode = self.root
        self.branch(currNode, substring, L-i-1, 0)

    max_repeat = max(self.repeats.iterkeys(), key=len)
    print "Max repeat is", len(max_repeat), ":", max_repeat, "at locations:", self.repeats[max_repeat]

def branch(self, currNode, substring, pos, repeat):

    if currNode.suffix != '':
        currNode.out[currNode.suffix[0]] = self.Node(currNode.position, currNode.suffix[1:])
        currNode.suffix = ''
        currNode.position = None

    if substring[0] not in currNode.out:

        currNode.out[substring[0]] = self.Node(pos, substring[1:])

        if repeat >= self.max_repeat:
            for node in currNode.out:
                self.repeats.setdefault(self.text[pos:pos+repeat], []).append(currNode.out[node].position)
            self.max_repeat = repeat

    else:

        newNode = currNode.out[substring[0]]
        self.branch(newNode, substring[1:], pos, repeat+1)

**第二版** - 认为大量字符串切片的持续保存可能是问题,我使用字符串缓冲区来实现所有切片。但是,这个版本几乎立即为substring = buffer(self.text,i-1)+" $"

提供 MemoryError
class SuffixTree(object):

    class Node(object):
        def __init__(self, position, suffix):
            self.position = position
            self.suffix = suffix
            self.out = {}

    def __init__(self, text):

        self.text = text
        self.max_repeat = 2
        self.repeats = {}
        self.root = self.Node(None, '')
        L = len(self.text)

        for i in xrange(L,0,-1):

            substring = buffer(self.text, i-1) + "$"
            #print substring
            currNode = self.root
            self.branch(currNode, substring, i-1, 0)

        max_repeat = max(self.repeats.iterkeys(), key=len)
        print "Max repeat is", len(max_repeat), ":", max_repeat, "at locations:", self.repeats[max_repeat]
        #print self.repeats

    def branch(self, currNode, substring, pos, repeat):

        if currNode.suffix != '':
            currNode.out[currNode.suffix[0]] = self.Node(currNode.position, buffer(currNode.suffix,1))
            currNode.suffix = ''
            currNode.position = None
        if substring[0] not in currNode.out:

            currNode.out[substring[0]] = self.Node(pos, buffer(substring,1))

            if repeat >= self.max_repeat:
                for node in currNode.out:
                    self.repeats.setdefault(buffer(self.text,pos,repeat), []).append(currNode.out[node].position)
                self.max_repeat = repeat

        else:

            newNode = currNode.out[substring[0]]
            self.branch(newNode, buffer(substring,1), pos, repeat+1)

我对缓冲区的理解是否有误?我认为使用它们会有助于我的程序所带来的内存问题,而不是让它变得更糟。

2 个答案:

答案 0 :(得分:0)

使用序列数据可能会占用大量内存,尤其是在使用数十GB或更大范围的fastq文件时。在某个时刻,您只需要使用具有更多RAM的机器。由于您未提供文件大小信息或有关计算资源的信息,因此无法确定是否属于这种情况。如果有机会请提供该信息。

无论如何,您似乎应该使用一些Bio python工具,这将使处理序列数据更加高效。这是因为Bio python的大部分都使用了C数据结构。

首先,您应该将序列表示为Seq,而不是字符串。

from Bio.Seq import Seq

sequence = Seq('ACTG')

其次,后缀树是trie的完美工作。

Trie - Wikipedia

from Bio import trie

self.out = trie.trie()
# You can work with this object just as you would with a dictionary.
# self.out[key] = value

使用这些biopython数据结构可以提高内存效率,在python中处理序列数据时,这只是一个很好的做法。

另外,我不确定你的最终目标是什么,但你可能想要研究更高效的后缀数组。许多从头组装商如ABySS使用它进行组装。

答案 1 :(得分:0)

将“$”添加到缓冲区就是杀死它的原因。这导致它将自己强制转换为字符串,这导致所有相同的复制。如果你真的需要附加字符,你可以尝试使用缓冲区列表,而不是实际将字符附加到单个缓冲区。