比较字符串列表中字符串中每个字符的最快方法

Fastest method to compare each character in string in a list of strings

我正在使用一个生物信息学工具,并使用两个循环来迭代每个字符来构建它。

输入(即 seq1 和序列)是长度相同的核苷酸串,例如 'AGATGCTAGTA'sequence_info 是所有序列的列表。

它非常慢,所以我通过使用 continue 而不是添加零并将 bio_array 存储为 numpy 数组来提高速度。这是新代码。

for (sequence, sequence_location) in sequence_info:
    value = slow_function(seq1, sequence)

def slow_function(seq1,sequence):
    calc=0
    for i,nt in enumerate(seq1):
        if nt == sequence[i]:
            continue
        else:
            calc += bio_array[i]
    return float(calc)

在 jupyter 笔记本中使用 %%timeit 它仍然是 100ms。我需要它在 1-5ms 左右或以下。我尝试将函数转换为迭代器并使用列表 comprehensions/map 而不是使用循环。但这些方法并没有产生重大影响。

我认为可能可以使用 numpy,但我无法通过查看文档或在 Whosebug 上找到可以使用的方法。如果序列中存在不匹配,我需要将 bio_array 中的特定值加在一起,因此我需要单独比较字符串中的每个字符值。

使这段代码的速度尽可能快的最佳方法是什么?

如果我没理解错的话,你的问题是你希望根据两个字符串序列不匹配的位置来对数组的元素求和。您可以简单地创建序列的字符数组,然后使用 numpy 条件索引来获取不匹配的值。这是一个简化的例子:

seq_a = np.array(list('ABCDEFGH'))
seq_b = np.array(list('ABCZEFZH'))
bio_array = np.array([1, 5, 9, 4, 3, 8, 2, 7])

然后,在 seq_aseq_b 之间进行逐元素比较,得到:

>>> seq_a != seq_b
array([False, False, False, True, False, False, True, False])

然后您可以使用此结果索引 bio_array 以获得相关值,然后将它们相加:

>>> bio_array[seq_a != seq_b]
array([4, 2])

>>> bio_array[seq_a != seq_b].sum()
6

你应该接受@sshashank124 的回答,但这里有一些代码可以快速显示发生了什么以及它有多大不同:

import numpy as np
from timeit import timeit


def slow_function(seq1, seq2, costs):
    calc = 0
    for i, nt in enumerate(seq1):
        if nt == seq2[i]:
            continue
        else:
            calc += costs[i]
    return float(calc)


def shorter_slow_function(seq1, seq2, costs):
    return sum(costs[i] for i in range(len(seq1)) if seq1[i] != seq2[i])


def faster_numpy_function(seq1, seq2, costs):
    return costs[seq1 != seq2].sum()


x = np.array(list('ABCDE'))
y = np.array(list('XBCDY'))
c = np.array([1.0, 2.0, 3.0, 4.0, 5.0])


print(timeit(lambda: slow_function(x, y, c)))
print(timeit(lambda: shorter_slow_function(x, y, c)))
print(timeit(lambda: faster_numpy_function(x, y, c)))

结果:

6.7421024
6.665790399999999
5.321171700000001