【问题标题】:Calculate similarity between list of words计算单词列表之间的相似度
【发布时间】:2019-08-05 08:33:35
【问题描述】:

我想计算两个单词列表之间的相似度,例如:

['email','user','this','email','address','customer']

类似于此列表:

['email','mail','address','netmail']

我希望获得比其他列表更高百分比的相似度,例如: ['address','ip','network'] 即使 address 存在于列表中。

【问题讨论】:

  • 你想要的输出是什么?
  • 相似度百分比,例如 80% 或更多
  • 你找到余弦相似度了吗?
  • 对于每个单词或单词列表?
  • 例如两个词是 100% 匹配,1 几乎是 80-90,其余的不匹配,应该输出什么?

标签: python data-mining text-mining similarity


【解决方案1】:

由于您还没有真正能够演示水晶输出,这是我最好的镜头:

list_A = ['email','user','this','email','address','customer']
list_B = ['email','mail','address','netmail']

在上面的两个列表中,我们会发现列表中每个元素与其余元素的余弦相似度。即email 来自list_Blist_A 中的每个元素:

def word2vec(word):
    from collections import Counter
    from math import sqrt

    # count the characters in word
    cw = Counter(word)
    # precomputes a set of the different characters
    sw = set(cw)
    # precomputes the "length" of the word vector
    lw = sqrt(sum(c*c for c in cw.values()))

    # return a tuple
    return cw, sw, lw

def cosdis(v1, v2):
    # which characters are common to the two words?
    common = v1[1].intersection(v2[1])
    # by definition of cosine distance we have
    return sum(v1[0][ch]*v2[0][ch] for ch in common)/v1[2]/v2[2]


list_A = ['email','user','this','email','address','customer']
list_B = ['email','mail','address','netmail']

threshold = 0.80     # if needed
for key in list_A:
    for word in list_B:
        try:
            # print(key)
            # print(word)
            res = cosdis(word2vec(word), word2vec(key))
            # print(res)
            print("The cosine similarity between : {} and : {} is: {}".format(word, key, res*100))
            # if res > threshold:
            #     print("Found a word with cosine distance > 80 : {} with original word: {}".format(word, key))
        except IndexError:
            pass

输出

The cosine similarity between : email and : email is: 100.0
The cosine similarity between : mail and : email is: 89.44271909999159
The cosine similarity between : address and : email is: 26.967994498529684
The cosine similarity between : netmail and : email is: 84.51542547285166
The cosine similarity between : email and : user is: 22.360679774997898
The cosine similarity between : mail and : user is: 0.0
The cosine similarity between : address and : user is: 60.30226891555272
The cosine similarity between : netmail and : user is: 18.89822365046136
The cosine similarity between : email and : this is: 22.360679774997898
The cosine similarity between : mail and : this is: 25.0
The cosine similarity between : address and : this is: 30.15113445777636
The cosine similarity between : netmail and : this is: 37.79644730092272
The cosine similarity between : email and : email is: 100.0
The cosine similarity between : mail and : email is: 89.44271909999159
The cosine similarity between : address and : email is: 26.967994498529684
The cosine similarity between : netmail and : email is: 84.51542547285166
The cosine similarity between : email and : address is: 26.967994498529684
The cosine similarity between : mail and : address is: 15.07556722888818
The cosine similarity between : address and : address is: 100.0
The cosine similarity between : netmail and : address is: 22.79211529192759
The cosine similarity between : email and : customer is: 31.62277660168379
The cosine similarity between : mail and : customer is: 17.677669529663685
The cosine similarity between : address and : customer is: 42.640143271122085
The cosine similarity between : netmail and : customer is: 40.08918628686365

注意:我还在代码中注释了threshold 部分,以防万一 如果它们的相似度超过某个特定值,您只需要这些词 阈值,即 80%

编辑

OP但我真正想做的不是逐字比较,而是逐个列表

使用Countermath

from collections import Counter
import math

counterA = Counter(list_A)
counterB = Counter(list_B)


def counter_cosine_similarity(c1, c2):
    terms = set(c1).union(c2)
    dotprod = sum(c1.get(k, 0) * c2.get(k, 0) for k in terms)
    magA = math.sqrt(sum(c1.get(k, 0)**2 for k in terms))
    magB = math.sqrt(sum(c2.get(k, 0)**2 for k in terms))
    return dotprod / (magA * magB)

print(counter_cosine_similarity(counterA, counterB) * 100)

输出

53.03300858899106

【讨论】:

  • 感谢您的解决方案,但我想要做的不是逐字比较,而是逐个列出:['email','mail','address','netmail' ] 与 ['email','user','this','email','address','customer'] 相比更半(百分比非常高,输出应该是 90% 或更多,因为大多数第一个列表中存在的单词也存在于第二个列表中),另一方面 ['email','mail','address','netmail'] 与 ['address','ip','network'] 相比即使地址存在于第二个列表中,输出的百分比也很低(百分比相对于其他列表)
  • @YounessDrissiSlimani by high 你是什么意思,我们应该只考虑 100% 匹配的词吗?到那时我们可以从两个列表中计算出有多少词是 100%,然后也许给出一个 est 百分比?
  • @YounessDrissiSlimani 太好了,如果有帮助,您可能会接受答案:meta.stackexchange.com/questions/5234/…欢呼
  • 您好@DirtyBit,我有一个问题,我尝试将 vocab=['address','ip'] 与两个列表 list_1 = "identifiant adresse ip address fixe horadatee cookie mac".split() 进行比较list_2="address ville".split() 分数对我来说并不完全正确,我希望 list_1 和 vocab 之间的余弦相似度更高 = 100%,因为 vocab 中的所有项目都等于 list_1 中的某些项目。
  • @YounessDrissiSlimani 我帮不上什么忙,请提出一个新问题,详细说明您已经拥有的详细信息以及您的尝试。
【解决方案2】:

您可以利用 Scikit-Learn(或其他 NLP)库的强大功能来完成此任务。下面的示例使用 CountVectorizer,但对于更复杂的文档分析,最好使用 TFIDF 矢量化器。

import numpy as np
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

def vect_cos(vect, test_list):
    """ Vectorise text and compute the cosine similarity """
    query_0 = vect.transform([' '.join(vect.get_feature_names())])
    query_1 = vect.transform(test_list)
    cos_sim = cosine_similarity(query_0.A, query_1.A)  # displays the resulting matrix
    return query_1, np.round(cos_sim.squeeze(), 3)

# Train the vectorizer
vocab=['email','user','this','email','address','customer']
vectoriser = CountVectorizer().fit(vocab)
vectoriser.vocabulary_ # show the word-matrix position pairs

# Analyse  list_1
list_1 = ['email','mail','address','netmail']
list_1_vect, list_1_cos = vect_cos(vectoriser, [' '.join(list_1)])

# Analyse list_2
list_2 = ['address','ip','network']
list_2_vect, list_2_cos = vect_cos(vectoriser, [' '.join(list_2)])

print('\nThe cosine similarity for the first list is {}.'.format(list_1_cos))
print('\nThe cosine similarity for the second list is {}.'.format(list_2_cos))

输出

The cosine similarity for the first list is 0.632.

The cosine similarity for the second list is 0.447.

编辑

如果您想计算“电子邮件”与任何其他字符串列表之间的余弦相似度,请使用“电子邮件”训练矢量化器,然后分析其他文档。

# Train the vectorizer
vocab=['email']
vectoriser = CountVectorizer().fit(vocab)

# Analyse  list_1
list_1 =['email','mail','address','netmail']
list_1_vect, list_1_cos = vect_cos(vectoriser, [' '.join(list_1)])
print('\nThe cosine similarity for the first list is {}.'.format(list_1_cos))

输出

The cosine similarity for the first list is 1.0.

【讨论】:

  • 很好的解决方案,但如果我训练 ['email','mail','address','netmail'] 并分析 ['email'] 输出为 0.5,对我来说正确答案是0.99 或 1.0,因为电子邮件的权重非常高。
  • 您显然误解了代码的工作原理。您必须使用词汇 ['email] 训练矢量化器,然后使用矢量化器分析 ['email','mail','address','netmail'] 以获得余弦相似度 1。请参阅更新的代码。
  • 啊,好吧,我明白了,可以训练 ['email'] 并且在分析 ['user','mail'] 时它是相似的,因为电子邮件就像邮件一样。有没有可能有单词向量?
  • 能不能把你最后一个问题说清楚,我不是很明白。
  • 我可以训练 ['email'] 并且当我测试与 ['user','mail'] 的相似性时,输出不应为 0.0,因为电子邮件等于 maining 中的邮件
猜你喜欢
  • 2018-05-20
  • 2017-03-19
  • 2012-03-11
  • 1970-01-01
  • 1970-01-01
  • 2018-08-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多