我有一个350,000
字符串数据库,平均长度约为500
。字符串不是由单词组成的,它们本质上是随机的字符组合。
我需要确保没有两个字符串太相似,其中相似性定义为编辑距离除以字符串的平均长度。划分是因为较小的字符串更容易接受较小的编辑距离。 如果出于性能原因使用不同的指标,则可以,但编辑距离是首选的基准指标。
天真地,我们用运行时O(a*b)
计算edit distance,其中a,b
是两个字符串的长度。我们对所有n^2
对执行此操作,这使得整体运行时间为O(n^2*a*b)
,显然对于n=350,000, a,b=500
来说太大了。
数据库采用从csv文件读取的Python列表的形式。如果可能的话,我想以Pythonic的方式处理它。
如何加快速度?我不知道天真算法需要花多长时间才能完成(大约几周)但理想情况下应该花不到一天的时间才能运行。
答案 0 :(得分:2)
我在python中写了一个简单的局部敏感散列算法的简短原型。但是有一些警告,你可能也想要优化一些部分。我们看到它们时会提到它们。
假设您的所有字符串都存储在strings
。
import random
from collections import Counter
MAX_LENGTH = 500
SAMPLING_LENGTH = 10
def bit_sampling(string, indices):
return ''.join([string[i] if i<len(string) else ' ' for i in indices])
indices = random.sample(range(MAX_LENGTH),SAMPLING_LENGTH)
hashes = [bit_sampling(string, indices) for string in strings]
counter = Counter(hashes)
most_common, count = counter.most_common()[0]
while count > 1:
dup_indices = [i for i, x in enumerate(hashes) if x == most_common]
# You can use dup_indices to check the edit distance for original groups here.
counter.pop(most_common)
most_common, count = counter.most_common()[0]
首先,这是位采样的一个轻微变体,最适合一般的汉明距离。理想情况下,如果所有字符串的长度相同,则可以给出汉明距离的理论概率。当两个字符串之间的汉明距离很小时,它们不太可能具有不同的散列。这可以通过参数SAMPLING_LENGTH
指定。较大的SAMPLING_LENGTH
将使得更可能将类似的字符串散列为不同的散列,但也会降低散列与相同散列的字符串非常相似的概率。对于汉明距离,您可以轻松地计算出这种权衡。
多次运行此代码段会增加您对没有类似字符串的信心,因为每次您都会尝试不同的地方。
为了满足您比较不同长度字符串的目的,一种可能的方法是在较短的字符串上留下填充空间并复制它们。
虽然此片段中的所有操作都是线性的(O(n)),但它仍然可能消耗大量内存和运行时间,并且可能会减少常量因子。
您可能还想考虑使用更复杂的局部敏感散列算法,例如此处调查的https://arxiv.org/pdf/1408.2927.pdf