python计算序列列表中存在和不存在子串的数量

时间:2013-11-16 15:53:14

标签: python string numpy scipy bioinformatics

你可以在这里获取数据! 2shared底部下载

我正在用python分析生物数据。

我已经写下了一个代码,用于在长字符串列表列表中查找匹配的子字符串。

子串在列表中,长度为7个核苷酸。

所以在列表中,从AAAAAAA到TTTTTTT,存在16384个基序(子串),排列A,C,G,T。

这段代码有一个for循环用于子串列表和嵌套在里面的长字符串列表。

它工作正常,但由于列表列表包含12000行,代码处理速度非常慢。

换句话说,提供有关AAAAAAA的信息,以及下一个AAAAAAC的信息需要2分钟。

因此需要16384个图案才能通过12000行2分钟,需要(16384 * 2 == 32768分钟 - > 546小时 - > 22天......)

我正在使用scipy和numpy来获得Pvalues。

我想要的是计算序列表中存在和不存在子串的数量

长字符串列表和代码如下:

list_of_lists_long  =  [
[BGN,    -0.054,     AGGCAGCTGCAGCCACCGCGGGGCCTCAGTGGGGGTCTCTGG....]
[ABCB7,  0.109,      GTCACATAAGACATTTTCTTTTTTTGTTGTTTTGGACTACAT....]
[GPR143, -0.137,     AGGGGATGTGCTGGGGGTCCAGACCCCATATTCCTCAGACTC....]
[PLP2,   -0.535,     GCGAACTTCCCTCATTTCTCTCTGCAATCTGCAAATAACTCC....]
[VSIG4,  0.13,       AAATGCCCCATTAGGCCAGGATCTGCTGACATAATTGCCTAG....]
[CCNB3,  -0.071,     CAGCAGCCACAGGGCTAAGCATGCATGTTAACAGGATCGGGA....]
[TCEAL3, 0.189,      TGCCTTTGGCCTTCCATTCTGATTTCTCTGATGAGAATACGA....]
....] #12000 lines

是否有更快的逻辑来更快地处理代码?

我需要你的帮助!

提前谢谢。

=====================================

有没有更简单的方法,没有实施任何其他事情?

我认为模式匹配的迭代是问题......

我试图找到的是在整个序列列表中出现长度为7个主题的次数,而不是发生的事情!因此,如果一个主题存在于一个字符串中,它是一个TRUE为bool,那么增加一个值AND FALSE,然后增加另一个值。

不是字符串中的图案数量。

6 个答案:

答案 0 :(得分:5)

很好的问题。这是一个典型的计算机科学问题。是的,确实有更好的算法。你的每个长字符串处理16384次。更好的方法是只处理每个长字符串一次。

不是在每个长字符串中搜索每个主题,而是应该记录每个长字符串中出现的主题。例如,如果您在以下字符串中搜索长度为2的图案:

s = 'ACGTAC'

然后你可以在长度为2的子串上运行一个循环并记录dict中存在哪些子串:

motifAppearances = {}
for i in range(len(s)-1):
    motif = s[i:i+2]                   # grab a length=2 substring
    if motif not in motifAppearances:
        motifAppearances[motif] = 0    # initialize the count
    motifAppearances[motif] += 1       # increment the count

现在你已经完整地处理了整个字符串,并找到了它中存在的所有图案。在这种情况下,结果dict看起来像:

motifAppearances = {'AC':2, 'CG':1, 'GT':1, 'TA':1}

为您的案件做类似的事情应该将您的运行时间减少16384倍。

答案 1 :(得分:3)

干净且非常快速的方式(使用OP数据约15秒)将使用CountVectorizerscikits-learn,因为它在引擎盖下使用numpy,例如:

from sklearn.feature_extraction.text import CountVectorizer

def make_chunks(s):
    width = 2
    return [s[i:i+width] for i in range(len(s)-width+1)]

l = ['ATTGCGGCTCACGAA', 'ACCTAGATACGACGG', 'CCCCTGTCCATGGTA']

vectorizer = CountVectorizer(tokenizer=make_chunks)
X = vectorizer.fit_transform(l)

现在X是一个稀疏矩阵,其中所有可能的块都是列,序列是行,其中每个值都是每个序列中给定块的出现次数:

>>> X.toarray()
# aa ac ag at ca cc cg ...
[[1  1  0  1  1  0  2  1 1 2 1 0 0 1 1 1]      # ATTGCGGCTCACGAA
 [0  3  1  1  0  1  2  1 2 0 1 0 2 0 0 0]      # ACCTAGATACGACGG
 [0  0  0  1  1  4  0  1 0 0 1 2 1 1 2 0]]     # CCCCTGTCCATGGTA

>>> (X.toarray()>0).astype(int)  # the same but counting only once per sequence
[[1 1 0 1 1 0 1 1 1 1 1 0 0 1 1 1]
 [0 1 1 1 0 1 1 1 1 0 1 0 1 0 0 0]
 [0 0 0 1 1 1 0 1 0 0 1 1 1 1 1 0]]

>>> vectorizer.get_feature_names()     # the columns(chunks)
[u'aa', u'ac', u'ag', u'at', u'ca', u'cc', u'cg', u'ct', u'ga', u'gc', u'gg', u'gt', u'ta', u'tc', u'tg', u'tt']

现在,您可以对列进行求和,屏蔽非值或您需要执行的任何操作,例如:

>>> X.sum(axis=0)
[[1 4 1 3 2 5 4 3 3 2 3 2 3 2 3 1]]

最后要查找给定主题出现的次数,必须找到相应主题/块的索引,然后在前一个总和中进行评估:

>>> index = vectorizer.vocabulary_.get('ag')    # 'ag' is your motif
2   # this means third column

在您的情况下,您必须将列表分为两部分(正值和负值)以包含停机条件。我使用DSM的答案列表进行了快速测试,我的计算机运行大约需要3-4秒。如果我使用12 000长度4000序列,那么它需要不到一分钟。

编辑:可以找到使用OP数据的整个代码here

答案 2 :(得分:2)

您的代码有几个奇怪的地方。

  1. 您所谓的“排列”看起来更像笛卡尔积,可以使用itertools.product计算。

  2. 因为Python是零索引的,所以字符串的第一个元素位于索引0处,因此如果字符串在开头就在那里,那么像i[2].find(sMotif) < 1这样的比较将返回True ,这似乎有点奇怪。

  3. 您的OddsRatio, PValueEnrichment计算在循环内部,但计数归零和print都没有,这意味着您要为每个计算累计计算它们新行,但没有对该信息做任何事情。

  4. 在典型案例中,您多次重新计算i[2].find(sMotif)次。该结果未缓存。


  5. 假设我理解你想要计算的数字 - 而且我可能错了,因为有些事你正在做我不理解的事情 - 我会翻转逻辑。而不是循环遍历每个主题并尝试在每一行中计算它,循环遍历每一行并查看其中的内容。这大约是行数的7 *而不是图案的数量*行数。

    例如:

    import random
    from itertools import product
    from collections import defaultdict, Counter
    
    N = 12000
    datalength = 400
    listoflists = [[str(i), random.uniform(-1, 1), 
                    ''.join([random.choice('AGCT') for c in range(datalength)])]
                   for i in range(N)]
    
    def chunk(seq, width):
        for i in range(len(seq)-width+1):
            yield seq[i:i+width]
    
    def count_motifs(datatriples, width=7):
        motif_counts_by_down = defaultdict(Counter)
        nonmotif_counts_by_down = defaultdict(Counter)
        all_motifs = set(''.join(p) for p in product('AGCT',repeat=width))
        for symbol, value, sdata in datatriples:
            down = value < -0.5
    
            # what did we see?
            motifs_seen = set(chunk(sdata, width))
            # what didn't we see?
            motifs_not_seen = all_motifs - motifs_seen
    
            # accumulate these
            motif_counts_by_down[down].update(motifs_seen)
            nonmotif_counts_by_down[down].update(motifs_not_seen)
    
        return motif_counts_by_down, nonmotif_counts_by_down
    

    (我降低线长只是为了让输出更快;如果线长10倍,代码需要10倍。)

    这在我的慢速笔记本电脑上生成(插入一些换行符后):

    >>> %time mot, nomot = count_motifs(listoflists, 7)
    CPU times: user 1min 50s, sys: 60 ms, total: 1min 50s
    Wall time: 1min 50s
    

    所以我认为完整问题大约需要20分钟,这对于如此少的代码来说并不坏。 (我们可以通过算术来加速motifs_not_seen部分,但这只会让我们得到两倍。)

    在一个更小的案例中,更容易看到输出:

    >>> mot, nomot = count_motifs(listoflists, 2)
    >>> mot
    defaultdict(<class 'collections.Counter'>, 
    {False: Counter({'CG': 61, 'TC': 58, 'AT': 55, 'GT': 54, 'CA': 53, 'GA': 53, 'AC': 52, 'CT': 51, 'CC': 50, 'AG': 49, 'TA': 48, 'GC': 47, 'GG': 45, 'TG': 45, 'AA': 43, 'TT': 40}), 
    True: Counter({'CT': 27, 'GT': 26, 'TC': 24, 'GC': 23, 'TA': 23, 'AC': 22, 'AG': 21, 'TG': 21, 'CC': 19, 'CG': 19, 'CA': 19, 'GG': 18, 'TT': 17, 'GA': 17, 'AA': 16, 'AT': 16})})
    >>> nomot
    defaultdict(<class 'collections.Counter'>, 
    {False: Counter({'TT': 31, 'AA': 28, 'GG': 26, 'TG': 26, 'GC': 24, 'TA': 23, 'AG': 22, 'CC': 21, 'CT': 20, 'AC': 19, 'GA': 18, 'CA': 18, 'GT': 17, 'AT': 16, 'TC': 13, 'CG': 10}), 
    True: Counter({'AA': 13, 'AT': 13, 'GA': 12, 'TT': 12, 'GG': 11, 'CC': 10, 'CA': 10, 'CG': 10, 'AG': 8, 'TG': 8, 'AC': 7, 'GC': 6, 'TA': 6, 'TC': 5, 'GT': 3, 'CT': 2})})
    

答案 3 :(得分:0)

基本上你的问题是序列比较。按顺序查找基序是Bioinfomatics中的一个基本问题。我想你可以搜索一些现有的算法或包。我在谷歌搜索关键词“motif match”,这是我在第一页中找到的: http://biowhat.ucsd.edu/homer/motif/ http://meme.nbcr.net/meme/doc/mast.html http://www.biomedcentral.com/1471-2105/8/189 http://www.benoslab.pitt.edu/stamp/

答案 4 :(得分:0)

我们写了一个名为Sylamer的工具。它计算相同给定长度的单词的出现次数。默认情况下,它会在排序基因的上下文中计算超几何测试,或者只输出计数。它可以对给定长度的所有可能单词执行此操作,但也可以指定较小的单词列表。它是用C语言编写的,并且非常适合快速处理。通过链接GNU科学库,我们可以非常快速地进行超几何计算。

答案 5 :(得分:-1)

我猜测问题是费希尔的确切测试。如果我在for循环之外计算P值,那么计算会变得更快。