快速检查大型数据库的编辑距离相似性
Quickly check large database for edit-distance similarity
我有一个包含 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 方式处理它。
如何加快速度?我不确定天真的算法需要多长时间才能完成(大约几周),但理想情况下应该用不到一天的时间 运行.
我在 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
将更有可能将相似的字符串散列为不同的散列,但也会降低将不太相似的字符串散列为相同散列的可能性。对于汉明距离,你可以很容易地计算出这个trade-off。
运行 多次使用此代码段可以增加您对没有相似字符串的信心,因为每次您都会在不同的地方进行采样。
为了满足您比较不同长度字符串的目的,一种可能的方法是在较短的字符串上左填充 space 并复制它们。
虽然此代码段中的所有操作都是线性的 (O(n)),但它仍可能消耗大量内存和 运行 时间,并且有可能减少常数因子。
您可能还想考虑使用更复杂的局部敏感哈希算法,例如此处调查的:https://arxiv.org/pdf/1408.2927.pdf
我有一个包含 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 方式处理它。
如何加快速度?我不确定天真的算法需要多长时间才能完成(大约几周),但理想情况下应该用不到一天的时间 运行.
我在 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
将更有可能将相似的字符串散列为不同的散列,但也会降低将不太相似的字符串散列为相同散列的可能性。对于汉明距离,你可以很容易地计算出这个trade-off。
运行 多次使用此代码段可以增加您对没有相似字符串的信心,因为每次您都会在不同的地方进行采样。
为了满足您比较不同长度字符串的目的,一种可能的方法是在较短的字符串上左填充 space 并复制它们。
虽然此代码段中的所有操作都是线性的 (O(n)),但它仍可能消耗大量内存和 运行 时间,并且有可能减少常数因子。
您可能还想考虑使用更复杂的局部敏感哈希算法,例如此处调查的:https://arxiv.org/pdf/1408.2927.pdf