使用python查找和删除公共子字符串

时间:2015-01-15 12:15:09

标签: python substring bioinformatics

所以我有两个引物序列:

fiveprime = "GATTCGAAGTCCACTATC"
threeprime = "TGAGTAGGACGGCACTATC"

我需要做的是当我有另一个序列时,我需要检查它是否包含一个部分 这些引物序列中的一个如果是,我需要去除匹配部分,留下不匹配部分进行进一步分析。

例如我的序列: CACTATC AAAAAAA 有五分之一的一部分。我需要找到这个公共子字符串,然后删除它只留下AAAAA

我遇到的问题是当你有一个像 CACTATC GAAG的序列时GAAG也在引物中,但不是引物序列的一部分,它仍然被删除。我试图通过确保找到的结构位于底漆的左侧并且三个引脚位于右侧来解决这个问题,例如:

使用 CACTATC GAAG,我们有2个常见结构 CACTATC GAAG 现在我可以将 CACTATC 与五个主要GATTCGAAGTC CACTATC 的结尾进行比较,并在匹配时告诉它是引物的一部分,然后将其删除。因此,当我们将 GAAG 与五个粉末的最后一端的长度进行比较时,它会给我们这个GATTCGAAGTCCAC TATC 这不匹配,所以 GAAG 可以继续进一步分析。

由于某些原因,我的脚本错误或无法正常工作。这个问题或建议还有其他解决方案吗?

def longestSubstringFinder(string1, string2):
answer = ""
len1, len2 = len(string1), len(string2)
for i in range(len1):
    match = ""
    for j in range(len2):
        if i + j < len1 and string1[i + j] == string2[j]:
            match += string2[j]
        else:
            if len(match) > len(answer): answer = match
            match = ""
return answer

def get_sequence(test, fiveprime, threeprime):
    if test == fiveprime:
        pass
    elif test == threeprime:
        pass
    elif test in fiveprime:
        pass
    elif test in threeprime:
        pass

        # find out if there is a matching part between the primers and the found
        # single stranded region, then calculates what part that is, and removes it
        # from the single stranded region
    else:
        overlap = longestSubstringFinder(fiveprime, test)
        l = len(overlap)

        if fiveprime[-l:] == test[:l]:
            check = test[l:]
        else:
            check = test

        overlap2 = longestSubstringFinder(check, threeprime)
        l = len(overlap2)

        if threeprime[:l] == check[-l:]:
            check2 = check[:-l]
            structure.append(check2)
        else:
            structure.append(check)

return structure

2 个答案:

答案 0 :(得分:1)

如果您选择适当的数据结构来表示您要查找的数据,我认为您的问题会更容易处理。我能想到的最好的是trie

这种结构的好处是它允许你在给定初始字母序列的情况下表示所有可能的匹配,所以如果你有序列AABAB,它将允许从初始A到A和B的遍历,但不是遍历从A到G或T.这样可以有效地找到部分匹配,因为trie中的任何一个点代表了那么多字母的匹配。

这个数据结构类似于:

class Trie(object):
    def __init__(self):
        self.children = {}

    def add_child(self, letter):
        if letter in self.children:
            return self.children[letter]
        else:
            child = Trie()
            self.children[letter] = child
            return child

    def traverse(self, letter):
        return self.children.get(letter, None)

然后您可以这样填充:

root = Trie()
current_positions = []
for letter in letters:
    current_positions = [
        position.add_child(letter)
        for position in current_positions
    ]
    current_positions.append(root.add_child(letter))

设置完所有这些后,您应该能够遍历此结构,直到遍历返回null。这将表示最长的当前匹配。字母的初始化将每个字母视为匹配的潜在起点,您也应如此。

然后,您可以搜索最长的子字符串匹配,如下所示:

class TrieSearch(object):
    def __init__(self, trie, starting_index):
        self.trie = trie
        self.starting_index = starting_index
        self.ending_index = starting_index + 1

    def update(self, letter):
        """ This returns a boolean indicating
            if the search can accept the letter """
        self.trie = self.trie.traverse(letter)
        if self.trie is not None:
            self.ending_index = self.ending_index + 1
            return True
        return False

    def get_match(self, letters):
        return letters[self.starting_index:self.ending_index]

def find_matches(root, letters):
    completed_matches = []
    current_matches = []

    for index, letter in enumerate(letters):
        new_current = []

        for current in current_matches:
            if current.update(letter):
                new_current.append(current)
            else:
                completed_matches.append(current)

        new_search_trie = root.traverse(letter)
        if new_search_trie is not None:
            new_current.append(TrieSearch(new_search_trie, index))

        current_matches = new_current

    all_matches = completed_matches + current_matches
    return [match.get_match(letters) for match in all_matches]

我已将所有这些放在a gist中,当使用threeprimefiveprime值初始化trie并且输入数据为CACTATCAAAAAAA时,结果为:

['CACTATC', 'ACTATC', 'CTATC', 'TATC', 'ATC', 'TC', 'CA', 'AA', 'AA', 'AA', 'AA', 'AA', 'AA', 'A']

由于您无疑会处理大量字符串,因此您可能需要查看一些更有效的通用字符串替换算法。 Aho-Corasick algorithm是此处概述的trie方法的扩展。还有Knuth-Morris-Pratt algorithm使用表而不是trie。这两种都是线性复杂度算法,与longestSubstringFinder方法使用的二次方法相比,它将是一个重大改进。

答案 1 :(得分:0)

问题是您的longestSubstringFinder已损坏。如果条件if len(match) > len(answer): answer = matchif len(match) > len(answer): answer = match,您只会检查False 。如果for j in range(len2):循环结束而没有发生这种情况,您只需丢弃match

修复很简单:在for j in range(len2):循环后添加for j in range(len2):

def longestSubstringFinder(string1, string2):
    answer = ""
    len1, len2 = len(string1), len(string2)
    for i in range(len1):
        match = ""
        for j in range(len2):
            if i + j < len1 and string1[i + j] == string2[j]:
                match += string2[j]
            else:
                if len(match) > len(answer): answer = match
                match = ""
        if len(match) > len(answer): answer = match # this was missing
    return answer