首页 > 解决方案 > 计算两个列表上的 Jaccard 相似度以在 Python 中返回最高相似度的词

问题描述

我有一个巨大的列表(包含约 250k 个单词),这是唯一的单词。(说清单1)

我有另一个列表,其中包含 5 个拼写错误的单词。(说清单2)

我需要找到 Jaccard 相似性(基于不同的 ngram)。在两个列表之间,并从 list1 返回最接近的匹配词。根据我在这个网站上找到的一些答案,我能够:

  1. 通过函数将两个列表拆分为 ngram。
  2. 计算第二个列表和第一个列表的第一个元素的 Jaccard 相似度。

这给了我一个有效的答案。但是,我无法从这里开始从 list1 返回最匹配的单词。我知道我需要将 ngram 函数应用于我的 list1 的每个元素。然后用 list2 计算 jaccard 相似度,并从中返回最大值元素。但无法通过循环实现它。这是我正在使用的代码:

def spell_correcter(list2=['word1', 'word2',... 'word5']):
    from sklearn.metrics import jaccard_similarity_score
    import re

    def find_ngrams(text: str, number: int=3) -> set:
    #returns a set of ngrams for the given string

        if not text:
            return set()

        str1 = ''.join(text)
        words = [f'  {x} ' for x in re.split(r'\W+', str1.lower()) if x.strip()]

        ngrams = set()

        for word in words:
            for x in range(0, len(word) - number + 1):
                ngrams.add(word[x:x+number])

        return ngrams


    def similarity(text1: str, text2: str, number: int=3) -> float:
    #Finds the similarity between 2 strings using ngrams.

        ngrams1 = find_ngrams(text1, number)
        ngrams2 = find_ngrams(text2, number)
        num_unique = len(ngrams1 | ngrams2)
        num_equal = len(ngrams1 & ngrams2)

        #Tried to compute for entire list1; very slow. Didn't execute
        #for i in range(0, len(text1)):
            #ngrams1 = find_ngrams(text1, number)
            #num_unique = len(ngrams1 | ngrams2)
            #num_equal = len(ngrams1 & ngrams2)
            #jaccard = float(num_equal) / float(num_unique)


        return float(num_equal) / float(num_unique)

    b = list2[0]
    a = similarity(list1, b)

    return a

有人可以帮忙处理这段代码吗?

标签: pythonsimilaritylevenshtein-distancen-gramsentence-similarity

解决方案


Shingling是通过获取连续的单词并将它们分组来创建单个对象的过程。
我们标记列表 1 并创建一个 ngram fo len(list2) 并计算每个 ngram 与列表 2 的 jaccard 相似度。这将给出列表 1 中最相似的单词与列表 2 中的单词:

def jaccard_similarity(list_x, list_y):
    set_x = set(list_x)
    set_y = set(list_y)
    intersection = set_x.intersection(set_y)
    union = set_x.union(set_y)
    return len(intersection) / len(union) if len(union) > 0 else 0

def shingling_jaccard_similarity(text_x, text_y, n):
    x = list(nltk.ngrams(tokenizer.tokenize(text_x), n))
    y = list(nltk.ngrams(tokenizer.tokenize(text_y), n))
    sim_score = jaccard_similarity(x,y)
    return sim_score

shingling_jaccard_similarity(list1, list2, len(list2))

推荐阅读