我正在使用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)+" $"
提供 MemoryErrorclass 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)
我对缓冲区的理解是否有误?我认为使用它们会有助于我的程序所带来的内存问题,而不是让它变得更糟。
答案 0 :(得分:0)
使用序列数据可能会占用大量内存,尤其是在使用数十GB或更大范围的fastq文件时。在某个时刻,您只需要使用具有更多RAM的机器。由于您未提供文件大小信息或有关计算资源的信息,因此无法确定是否属于这种情况。如果有机会请提供该信息。
无论如何,您似乎应该使用一些Bio python工具,这将使处理序列数据更加高效。这是因为Bio python的大部分都使用了C数据结构。
首先,您应该将序列表示为Seq,而不是字符串。
from Bio.Seq import Seq
sequence = Seq('ACTG')
其次,后缀树是trie的完美工作。
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)
将“$”添加到缓冲区就是杀死它的原因。这导致它将自己强制转换为字符串,这导致所有相同的复制。如果你真的需要附加字符,你可以尝试使用缓冲区列表,而不是实际将字符附加到单个缓冲区。