在Python中找到所有句子中最相似的句子

4

欢迎提供建议/参考链接/代码。

我有一个数据集,其中包含超过1500个句子。我正在尝试找到最佳方法来找出所有句子中最相似的句子。

我尝试过的方法

  1. 我尝试了K均值算法,它将相似的句子分组为簇。但是我发现有一个缺点,就是我必须传递K来创建簇。很难猜测K。我尝试了elbo方法来猜测簇,但是将所有数据归为一组是不够的。在这种方法中,我得到了所有数据分组的结果。我想要的是相似度高于0.90%的数据应返回带有ID的数据。

  2. 我尝试了余弦相似性,在其中使用TfidfVectorizer创建矩阵,然后通过余弦相似性进行比较。即使使用这种方法,也无法正常工作。

我在寻找什么

我想要一种方法,在其中可以传递一个阈值,例如0.90,返回所有行中相似度高于0.90%的数据作为结果。

Data Sample
ID    |   DESCRIPTION
-----------------------------
10    | Cancel ASN WMS Cancel ASN   
11    | MAXPREDO Validation is corect
12    | Move to QC  
13    | Cancel ASN WMS Cancel ASN   
14    | MAXPREDO Validation is right
15    | Verify files are sent every hours for this interface from Optima
16    | MAXPREDO Validation are correct
17    | Move to QC  
18    | Verify files are not sent

期望结果

与0.90%相似的上述数据应该以ID为结果。

ID    |   DESCRIPTION
-----------------------------
10    | Cancel ASN WMS Cancel ASN
13    | Cancel ASN WMS Cancel ASN
11    | MAXPREDO Validation is corect  # even spelling is not correct
14    | MAXPREDO Validation is right
16    | MAXPREDO Validation are correct
12    | Move to QC  
17    | Move to QC  
3个回答

11

为什么在使用余弦相似度和TFIDF向量化时,它对您无效?

我尝试了一下,使用这段代码可以正常工作:

import pandas as pd
import numpy as np

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

df = pd.DataFrame(columns=["ID","DESCRIPTION"], data=np.matrix([[10,"Cancel ASN WMS Cancel ASN"],
                                                                [11,"MAXPREDO Validation is corect"],
                                                                [12,"Move to QC"],
                                                                [13,"Cancel ASN WMS Cancel ASN"],
                                                                [14,"MAXPREDO Validation is right"],
                                                                [15,"Verify files are sent every hours for this interface from Optima"],
                                                                [16,"MAXPREDO Validation are correct"],
                                                                [17,"Move to QC"],
                                                                [18,"Verify files are not sent"]
                                                                ]))

corpus = list(df["DESCRIPTION"].values)

vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(corpus)

threshold = 0.4

for x in range(0,X.shape[0]):
  for y in range(x,X.shape[0]):
    if(x!=y):
      if(cosine_similarity(X[x],X[y])>threshold):
        print(df["ID"][x],":",corpus[x])
        print(df["ID"][y],":",corpus[y])
        print("Cosine similarity:",cosine_similarity(X[x],X[y]))
        print()

阈值也可以进行调整,但如果将阈值设为0.9,则不会产生您想要的结果。

当阈值为0.4时的输出结果为:

10 : Cancel ASN WMS Cancel ASN
13 : Cancel ASN WMS Cancel ASN
Cosine similarity: [[1.]]

11 : MAXPREDO Validation is corect
14 : MAXPREDO Validation is right
Cosine similarity: [[0.64183024]]

12 : Move to QC
17 : Move to QC
Cosine similarity: [[1.]]

15 : Verify files are sent every hours for this interface from Optima
18 : Verify files are not sent
Cosine similarity: [[0.44897995]]

如果阈值为0.39,则输出中包含所有预期的句子特征,但还可以找到一个索引为[15,18]的额外对:

10 : Cancel ASN WMS Cancel ASN
13 : Cancel ASN WMS Cancel ASN
Cosine similarity: [[1.]]

11 : MAXPREDO Validation is corect
14 : MAXPREDO Validation is right
Cosine similarity: [[0.64183024]]

11 : MAXPREDO Validation is corect
16 : MAXPREDO Validation are correct
Cosine similarity: [[0.39895808]]

12 : Move to QC
17 : Move to QC
Cosine similarity: [[1.]]

14 : MAXPREDO Validation is right
16 : MAXPREDO Validation are correct
Cosine similarity: [[0.39895808]]

15 : Verify files are sent every hours for this interface from Optima
18 : Verify files are not sent
Cosine similarity: [[0.44897995]]

这真是太令人印象深刻了,而且运行得非常好。我遇到了一些挑战,比如: 1)有些句子重复超过两次,第一个句子不断重复 例如:索引[11]在[11, 14]和[11, 16]中重复出现。 2)代码运行时行数超过1500,在我只处理500行的情况下,需要大约1分钟才能完成任务。当找到重复的句子时,一个ID会被重复。 - vivek
我很高兴能够帮助您。如果我的答案对您有所帮助,请用绿色复选标记将其标记为“已接受的答案”。 - Kim Tang
当然,我会将此标记为答案。但在此之前,您能否建议我如何在发现重复时提高速度和行的重复? - vivek
1
对于1500行数据,需要超过20分钟的时间。 - vivek
我不确定如何提高速度。我建议您开一个新的问题,以速度为重点,并在那里包括您尝试过什么的信息,这样其他人就可以帮助您。 - Kim Tang
显示剩余2条评论

3

可以使用这个Python 3库计算句子相似度:https://github.com/UKPLab/sentence-transformers

以下是来自https://www.sbert.net/docs/usage/semantic_textual_similarity.html的代码示例:

from sentence_transformers import SentenceTransformer, util
model = SentenceTransformer('paraphrase-MiniLM-L12-v2')

# Two lists of sentences
sentences1 = ['The cat sits outside',
             'A man is playing guitar',
             'The new movie is awesome']

sentences2 = ['The dog plays in the garden',
              'A woman watches TV',
              'The new movie is so great']

#Compute embedding for both lists
embeddings1 = model.encode(sentences1, convert_to_tensor=True)
embeddings2 = model.encode(sentences2, convert_to_tensor=True)

#Compute cosine-similarits
cosine_scores = util.pytorch_cos_sim(embeddings1, embeddings2)

#Output the pairs with their score
for i in range(len(sentences1)):
    print("{} \t\t {} \t\t Score: {:.4f}".format(sentences1[i], sentences2[i], cosine_scores[i][i]))

这个库包含最先进的句子嵌入模型。

请查看https://dev59.com/OFMI5IYBdhLWcg3wq9eL#68728666以执行句子聚类。


3
一种可能的方法是使用词嵌入来创建句子的向量表示。就像您使用预训练的词嵌入,让rnn层创建一个句子向量表示,其中每个句子的词嵌入被组合起来。然后您就有了一个向量,可以计算之间的距离。但是,您需要决定要设置哪个阈值,以便接受相似的句子,因为词嵌入的尺度并不固定。
更新
我进行了一些实验。在我看来,这是一个可行的方法,但是您可能希望自己找出它在您的情况下的工作效果。我在我的git repository中创建了一个示例。
此外,可以使用word-mover-distance算法完成此任务。您可以在这篇medium article中找到更多关于此主题的信息。

你能分享任何可以做参考的代码片段吗? - vivek
是的,我会看看能否设置一些东西。 - MichaelJanz
我已经仔细阅读了这个例子,看起来你正在使用RNN,代码非常出色。但我有些困惑,不知道如何将其进一步与我的工作联系起来。如果你能进一步解答我的问题,那就太好了。 - vivek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接