如何在词/事物词典中查找前 N 个相似词?

问题描述

我有一个要映射的 str 列表。这些词可能是“金属”或“圣帕特里克”。目标是针对此列表映射一个新字符串并找到前 N 个相似项。例如,如果我经过“圣帕特里克”,我想捕获“圣帕特里克”或“圣帕特里克”。

我知道有 gensim 和 fastText,而且我有一种直觉,我应该选择余弦相似度(或者如果有其他建议,我会全神贯注)。我主要处理时间序列,gensim 模型训练似乎不喜欢单词列表。

接下来我的目标是什么?

解决方法

首先,您必须确定您对正交相似性还是语义相似性感兴趣。

正交相似度

在这种情况下,您对两个字符串之间的距离进行评分。有 various metrics 用于计算编辑距离。 Levenshtein distance 是最常见的:您可以找到各种 Python 实现,例如 this

“gold”与“good”相似,但与“metal”不同。

语义相似性

在这种情况下,您测量两个字符串具有相似含义的程度。

fastText 和其他词嵌入属于这种情况,即使它们也考虑了正交方面。

“黄金”更类似于“金属”而不是“好”。

如果您的列表中的单词数量有限,您可以使用 existing word embedding,针对您的语言进行预训练。基于此词嵌入,您可以计算列表中每个词/句子的词向量,然后使用余弦相似度将新词的向量与列表中的向量进行比较。

import fasttext
import numpy as np

# download English pretrained model
fasttext.util.download_model('en',if_exists='ignore')
ft = fasttext.load_model('cc.en.300.bin')

def cos_sim(a,b):
    """Takes 2 vectors a,b and returns the cosine similarity according 
    to the definition of the dot product
    (https://masongallo.github.io/machine/learning,/python/2016/07/29/cosine-similarity.html)
    """
    dot_product = np.dot(a,b)
    norm_a = np.linalg.norm(a)
    norm_b = np.linalg.norm(b)
    return dot_product / (norm_a * norm_b)

def compare_word(w,words_vectors):
    """
    Compares new word with those in the words vectors dictionary
    """
    vec=ft.get_sentence_vector(w)
    return {w1:cos_sim(vec,vec1) for w1,vec1 in words_vectors.items()}

# define your word list
words_list=[ "metal","st. patrick","health"]

# compute words vectors and save them into a dictionary.
# since there are multiwords expressions,we use get_sentence_vector method
# instead,you can use  get_word_vector method
words_vectors={w:ft.get_sentence_vector(w) for  w in words_list}

# try compare_word function!

compare_word('saint patrick',words_vectors)
# output: {'metal': 0.13774191,'st. patrick': 0.78390956,'health': 0.10316559}

compare_word('copper',words_vectors)
# output: {'metal': 0.6028242,'st. patrick': 0.16589196,'health': 0.10199054}

compare_word('ireland',words_vectors)
# output: {'metal': 0.092361264,'st. patrick': 0.3721483,'health': 0.118174866}

compare_word('disease',words_vectors)
# output: {'metal': 0.10678574,'st. patrick': 0.07039305,'health': 0.4192972}