簡體   English   中英

嵌套枚舉 for 循環到理解列表

[英]Nested enumerated for loops to comprehension list

我使用的是textdistance.needleman_wunsch.normalized_distancetextdistance庫( https://github.com/life4/textdistance )。 我將它與Scipy庫中的cdist一起使用來計算序列對距離。 但是由於嵌套的枚舉 for 循環,該過程非常長。

在這里,您可以找到textdistance庫中使用的需要時間的代碼,我想知道您是否知道如何加速嵌套的 for 循環,也許使用列表理解?

s1 = "sentence1"
s2 = "sentevfers2"
gap = 1


def sim_func(*elements):
    """Return True if all sequences are equal.
    """
    try:
        # for hashable elements
        return len(set(elements)) == 1
    except TypeError:
        # for unhashable elements
        for e1, e2 in zip(elements, elements[1:]):
            if e1 != e2:
                return False
        return True


dist_mat = numpy.zeros(
    (len(s1) + 1, len(s2) + 1),
    dtype=numpy.float,
)

# DP initialization
for i in range(len(s1) + 1):
    dist_mat[i, 0] = -(i * gap)

# DP initialization
for j in range(len(s2) + 1):
    dist_mat[0, j] = -(j * gap)

""" Possible enhancement with list comprehension ? """
# Needleman-Wunsch DP calculation
for i, c1 in enumerate(s1, 1):
    for j, c2 in enumerate(s2, 1):
        match = dist_mat[i - 1, j - 1] + sim_func(c1, c2)
        delete = dist_mat[i - 1, j] - gap
        insert = dist_mat[i, j - 1] - gap
        dist_mat[i, j] = max(match, delete, insert)
distance = dist_mat[dist_mat.shape[0] - 1, dist_mat.shape[1] - 1]
print(distance)

由於以下幾個原因,此代碼很慢:

  • 它(可能)在 CPython 中執行並用純 Python 編寫,這是一個慢速解釋器,不是為這種數字代碼設計的
  • sim_func是比較各種元素的通用方法,但也非常低效(分配、散列、異常處理和字符串操作)。

代碼無法輕松並行化,因此矢量化 numpy。 但是,您可以使用 Numba 來加快速度。 僅當輸入字符串非常大或此處理執行大量時間時才值得。 如果不是這種情況,請使用更合適的編程語言(例如 C、C++、D、Rust 等)或專用於此的本機 Python 模塊

這是優化后的 Numba 代碼:

s1 = "sentence1"
s2 = "sentevfers2"
gap = 1  # Assume this is an integer

@njit
def NeedlemanWunschDP(dist_mat, s1, s2):
    for i in range(1, len(s1)+1):
        for j in range(1, len(s2)+1):
            match = dist_mat[i - 1, j - 1] + (s1[i-1] == s2[j-1])
            delete = dist_mat[i - 1, j] - gap
            insert = dist_mat[i, j - 1] - gap
            dist_mat[i, j] = max(match, delete, insert)

dist_mat = numpy.empty(
    (len(s1) + 1, len(s2) + 1),
    dtype=numpy.int64,
)

# DP initialization
for i in range(len(s1) + 1):
    dist_mat[i, 0] = -(i * gap)

# DP initialization
for j in range(len(s2) + 1):
    dist_mat[0, j] = -(j * gap)

# Transform the strings to fast integer arrays
tmp_s1 = numpy.array([ord(e) for e in s1], dtype=numpy.int64)
tmp_s2 = numpy.array([ord(e) for e in s2], dtype=numpy.int64)
# Needleman-Wunsch DP calculation
NeedlemanWunschDP(dist_mat, tmp_s1, tmp_s2)
distance = dist_mat[dist_mat.shape[0] - 1, dist_mat.shape[1] - 1]
print(distance)

在我的機器上, NeedlemanWunschDP的編譯時間大約需要 400 毫秒,但生成的代碼在大字符串上要快 1800 倍以上

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM