簡體   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