繁体   English   中英

在 python 中使用后缀树

[英]Working with suffix trees in python

我对 python 比较陌生,并且开始使用后缀树。 我可以构建它们,但是当字符串变大时我遇到了 memory 问题。 我知道它们可用于处理大小为 4^10 或 4^12 的 DNA 字符串,但每当我尝试实施一种方法时,我都会遇到 memory 问题。

这是我生成字符串和后缀树的代码。

import random

def get_string(length):
    string=""
    for i in range(length):
        string += random.choice("ATGC")
    return string

word=get_string(4**4)+"$"

def suffixtree(string):
    for i in xrange(len(string)):
        if tree.has_key(string[i]):
            tree[string[i]].append([string[i+1:]][0])
        else:
            tree[string[i]]=[string[i+1:]]
    return tree

tree={}
suffixtree(word)

当我达到 4**8 左右时,我遇到了严重的 memory 问题。 我对此很陌生,所以我确定我在存储这些东西时遗漏了一些东西。 任何建议将不胜感激。

请注意:我想进行字符串搜索以在非常大的字符串中查找匹配的字符串。 搜索字符串匹配大小为 16。因此,这将在大字符串中查找大小为 16 的字符串,然后移动到下一个字符串并执行另一次搜索。 由于我将进行大量搜索,因此建议使用后缀树。

非常感谢

这在我看来不像一棵树。 看起来您正在生成所有可能的后缀,并将它们存储在哈希表中。

如果您使用实际的树,您可能会获得更小的 memory 性能。 我建议使用库实现。

正如其他人已经说过的,您正在构建的数据结构不是后缀树。 但是, memory 问题主要源于您的数据结构涉及大量显式字符串副本这一事实。 像这样的电话

string[i+1:]

i+1开始创建 substring 的实际(深)副本。

如果您仍然对构建原始数据结构感兴趣(无论它的用途是什么),一个好的解决方案是使用缓冲区而不是字符串副本。 您的算法将如下所示:

def suffixtree(string):
    N = len(string)
    for i in xrange(N):
        if tree.has_key(string[i]):
            tree[string[i]].append(buffer(string,i+1,N))
        else:
            tree[string[i]]=[buffer(string,i+1,N)]
    return tree

我尝试将其嵌入到您的代码的 rest 中,并确认即使总长度为 8^11 个字符,它也需要明显少于 1 GB 的主 memory。

请注意,即使您切换到实际的后缀树,这也可能是相关的。 正确的后缀树实现不会在树的边缘存储副本(甚至缓冲区); 但是,在构建树期间,您可能需要大量字符串的临时副本。 为这些使用buffer类型是一个很好的主意,可以避免为所有不必要的显式字符串副本给垃圾收集器带来沉重负担。

如果您的 memory 问题在于创建后缀树,您确定需要一个吗? 您可以像这样在一个字符串中找到所有匹配项:

word=get_string(4**12)+"$"

def matcher(word, match_string):
    positions = [-1]
    while 1:
        positions.append(word.find(match_string, positions[-1] + 1))
        if positions[-1] == -1:
            return positions[1:-1]

print matcher(word,'AAAAAAAAAAAA')
[13331731, 13331732, 13331733]
print matcher('AACTATAAATTTACCA','AT')
[4, 8]

我的机器很旧,运行 4^12 字符串需要 30 秒。 我使用了一个 12 位数字的目标,所以会有一些匹配。 此解决方案还将找到重叠的结果——如果有的话。

是您可以尝试的后缀树模块,如下所示:

import suffixtree
stree = suffixtree.SuffixTree(word)
print stree.find_substring("AAAAAAAAAAAA")

不幸的是,我的机器太慢了,无法用长字符串正确地测试它。 但是大概一旦构建了后缀树,搜索就会非常快,所以对于大量搜索来说,这应该是一个很好的选择。 此外find_substring只返回第一个匹配项(不知道这是否是一个问题,我相信你可以轻松地适应它)。

更新:将字符串拆分成更小的后缀树,从而避免 memory 问题

因此,如果您需要对 4^12 长度的字符串进行 1000 万次搜索,我们显然不想等待 9.5 年(标准简单搜索,我首先建议,在我的慢速机器上......)。 然而,我们仍然可以使用后缀树(因此更快),并避免 memory 问题。 将大字符串拆分为可管理的块(我们知道机器 memory 可以处理)并将一个块变成后缀树,搜索 1000 万次,然后丢弃该块并移动到下一个。 我们还需要记住搜索每个块之间的重叠。 我写了一些代码来做到这一点(它假设要搜索的大字符串, word是我们最大可管理字符串长度max_length的倍数,你必须调整代码以在最后检查余数,如果这是不是这样):

def split_find(word,search_words,max_length):
    number_sub_trees = len(word)/max_length
    matches = {}
    for i in xrange(0,number_sub_trees):
        stree = suffixtree.SuffixTree(word[max_length*i:max_length*(i+1)])
        for search in search_words:
            if search not in matches:
                match = stree.find_substring(search)
                if match > -1:
                    matches[search] = match + max_length*i,i
            if i < number_sub_trees:
                match = word[max_length*(i+1) - len(search):max_length*(i+1) + len(search)].find(search)
                if match > -1:
                    matches[search] = match + max_length*i,i
    return matches

word=get_string(4**12)
search_words = ['AAAAAAAAAAAAAAAA'] #list of all words to find matches for
max_length = 4**10 #as large as your machine can cope with (multiple of word)
print split_find(word,search_words,max_length)

在此示例中,我将最大后缀树长度限制为 4^10,这大约需要 700MB。 使用此代码,对于一个 4^12 长度的字符串,1000 万次搜索大约需要 13 个小时(完整搜索,零匹配,因此如果有匹配,速度会更快)。 但是,作为其中的一部分,我们需要构建 100 棵后缀树,这大约需要 ..100*41sec= 1 小时。

所以总运行时间约为 14 小时,没有 memory 问题......比 9.5 年有了很大改进。 请注意,我在具有 1GB RAM 的 1.6GHz CPU 上运行此程序,因此您应该能够做得比这更好!

你得到 memory 问题的原因是对于输入'banana'你正在生成{'b': ['anana$'], 'a': ['nana$', 'na$', '$'], 'n': ['ana$', 'a$']} 那不是树结构。 您已创建并存储在其中一个列表中的所有可能的输入后缀。 这需要 O(n^2) 存储空间。 此外,为了使后缀树正常工作,您希望叶节点为您提供索引位置。

你想要得到的结果{'banana$': 0, 'a': {'$': 5, 'na': {'$': 3, 'na$': 1}}, 'na': {'$': 4, 'na$': 2}} (这是一种优化表示;一种更简单的方法将我们限制在单字符标签上。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM