句子相似度预测


15

我正在寻求解决以下问题:我有一组句子作为我的数据集,并且我希望能够键入一个新句子,并找到该新句子与数据集中最相似的句子。一个示例如下所示:

新句子:“ I opened a new mailbox

基于数据集的预测:

Sentence                       | Similarity
A dog ate poop                   0%
A mailbox is good                50%
A mailbox was opened by me       80%

我已经读到余弦相似度可以用来解决与tf-idf配对的这类问题(RNN不应对基本方法带来重大改进),或者word2vec也可以用于相似的问题。那些在这种特定情况下实际可行吗?是否有其他技术/算法可以解决此问题(最好使用Python和SKLearn,但我也愿意学习TensorFlow)?


一定要检查伯特。这是一个不错的实现。它确实满足您的期望,并且效果很好
GioGio

Answers:


26

可以使用Word2vec和Doc2vec解决您的问题。Doc2vec会产生更好的结果,因为在训练模型时会考虑句子。

Doc2vec解决方案
您可以通过此链接训练doc2vec模型。您可能需要执行一些预处理步骤,例如删除所有停用词(诸如“ the”,“ an”等词,但不会给句子增加太多含义)。训练好模型后,您可以使用以下代码查找相似的句子。

import gensim  

model = gensim.models.Doc2Vec.load('saved_doc2vec_model')  

new_sentence = "I opened a new mailbox".split(" ")  
model.docvecs.most_similar(positive=[model.infer_vector(new_sentence)],topn=5)

结果:

[('TRAIN_29670', 0.6352514028549194),
 ('TRAIN_678', 0.6344441771507263),
 ('TRAIN_12792', 0.6202734708786011),
 ('TRAIN_12062', 0.6163255572319031),
 ('TRAIN_9710', 0.6056315898895264)]

以上结果是的元组列表(label,cosine_similarity_score)。您可以通过执行将输出映射到句子train[29670]

请注意,如果您的doc2vec模型包含在新句子中找到的单词的嵌入,则上述方法只会产生良好的效果。如果您尝试为像这样的胡言乱语的句子获取相似性sdsf sdf f sdf sdfsdffg,它将给您带来很少的结果,但是这些可能不是实际的相似句子,因为您训练的模型在训练模型时可能没有看到这些胡言乱语的单词。因此,请尝试在尽可能多的句子上训练模型,以合并尽可能多的单词以获得更好的结果。

Word2vec解决方案
如果使用word2vec,则需要计算每个句子中所有单词的平均向量,并在向量之间使用余弦相似度。

def avg_sentence_vector(words, model, num_features, index2word_set):
    #function to average all words vectors in a given paragraph
    featureVec = np.zeros((num_features,), dtype="float32")
    nwords = 0

    for word in words:
        if word in index2word_set:
            nwords = nwords+1
            featureVec = np.add(featureVec, model[word])

    if nwords>0:
        featureVec = np.divide(featureVec, nwords)
    return featureVec

计算相似度

from sklearn.metrics.pairwise import cosine_similarity

#get average vector for sentence 1
sentence_1 = "this is sentence number one"
sentence_1_avg_vector = avg_sentence_vector(sentence_1.split(), model=word2vec_model, num_features=100)

#get average vector for sentence 2
sentence_2 = "this is sentence number two"
sentence_2_avg_vector = avg_sentence_vector(sentence_2.split(), model=word2vec_model, num_features=100)

sen1_sen2_similarity =  cosine_similarity(sentence_1_avg_vector,sentence_2_avg_vector)

谢谢!可以在周末进行此工作,但是乍看之下该解决方案确实很完美。荣誉!
lte__

我们是否需要对句子进行标记化以进行训练
pyd

是的,我们必须@pyd!sentence_1.split()一样。
哈曼

4

单词移动器的距离(WMD)是一种用于查找句子之间距离的算法。WMD基于单词嵌入(例如word2vec),这些单词嵌入将单词的语义翻译成密集的向量。

WMD距离测量两个文本文档之间的差异,这是一个文档的嵌入单词需要“移动”以到达另一文档的嵌入单词的最小距离。

例如:

在此处输入图片说明 来源:“从单词嵌入到文档距离”论文

gensim包大规模杀伤性武器的实现

对于您的问题,您可以将输入的句子与所有其他句子进行比较,然后返回WMD最低的句子。


2

您可以尝试使用sklearn的简单解决方案,并且可以正常运行。

  • 使用tfidfvectorizer获取每个文本的矢量表示

  • 使矢量化器适合您的数据,删除停用词。

  • 使用先前受过训练的矢量化器转换新条目

  • 计算此表示形式与数据集中元素的每种表示形式之间的余弦相似度

如果您有一个庞大的数据集,则可以在获取表示形式之后以及对新数据进行预测之前将其聚类(例如,使用scikit learning中的KMeans)。

此代码执行所有这些步骤。您可以在我的github repo上检查它。

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans
from sklearn.metrics import adjusted_rand_score
import numpy

texts = ["This first text talks about houses and dogs",
        "This is about airplanes and airlines",
        "This is about dogs and houses too, but also about trees",
        "Trees and dogs are main characters in this story",
        "This story is about batman and superman fighting each other", 
        "Nothing better than another story talking about airplanes, airlines and birds",
        "Superman defeats batman in the last round"]

# vectorization of the texts
vectorizer = TfidfVectorizer(stop_words="english")
X = vectorizer.fit_transform(texts)
# used words (axis in our multi-dimensional space)
words = vectorizer.get_feature_names()
print("words", words)


n_clusters=3
number_of_seeds_to_try=10
max_iter = 300
number_of_process=2 # seads are distributed
model = KMeans(n_clusters=n_clusters, max_iter=max_iter, n_init=number_of_seeds_to_try, n_jobs=number_of_process).fit(X)

labels = model.labels_
# indices of preferible words in each cluster
ordered_words = model.cluster_centers_.argsort()[:, ::-1]

print("centers:", model.cluster_centers_)
print("labels", labels)
print("intertia:", model.inertia_)

texts_per_cluster = numpy.zeros(n_clusters)
for i_cluster in range(n_clusters):
    for label in labels:
        if label==i_cluster:
            texts_per_cluster[i_cluster] +=1 

print("Top words per cluster:")
for i_cluster in range(n_clusters):
    print("Cluster:", i_cluster, "texts:", int(texts_per_cluster[i_cluster])),
    for term in ordered_words[i_cluster, :10]:
        print("\t"+words[term])

print("\n")
print("Prediction")

text_to_predict = "Why batman was defeated  by superman so easy?"
Y = vectorizer.transform([text_to_predict])
predicted_cluster = model.predict(Y)[0]
texts_per_cluster[predicted_cluster]+=1

print(text_to_predict)
print("Cluster:", predicted_cluster, "texts:", int(texts_per_cluster[predicted_cluster])),
for term in ordered_words[predicted_cluster, :10]:
print("\t"+words[term])

嘿,如果您能举例说明使用余弦相似性,那将是非常好的吗?
蒂多

嘿,难道不是第2部分首先出现,适合所有数据并使用它来转换每个文本吗?如果您可以举一个使用余弦相似性的例子,那将是非常不错的吗?
蒂多

1

最近在RNN模型中有一些基于变分自动编码器的工作。使用pytorch实现从连续空间生成句子github code
他们设法将一个句子的语义,句法全局特征压缩到某个潜在空间中,该潜在空间可能由有限的10到30个独立随机变量(因式分布)表示。
在这项工作中的新颖思想,他们在两个句子之间插值。结果非常惊人。


0

通用解决方案包括以下步骤:

  1. 特征化或句子的词嵌入。
  2. 在句子之间应用相似性度量。

nXnnXdd

嵌入每个单词的单词后,可以在每个句子上应用任何相似度度量,例如余弦相似度等,以衡量与其他句子的相似度。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.