Предсказание сходства предложений

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)?

lte__
источник
Определенно проверьте Берт . Вот хорошая реализация . Он делает именно то, что вы ищете, с довольно хорошими результатами
GioGio

Ответы:

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)
Harman
источник
Спасибо! Будет работать над этим в выходные, но решение кажется на первый взгляд идеальным. Престижность!
___
нужно ли токенизировать предложения для обучения
pyd
да @pyd мы должны! sentence_1.split()делает то же самое.
Харман
4

Word Mover's Distance (WMD) - это алгоритм для определения расстояния между предложениями. ОМУ основывается на встраивании слов (например, word2vec), которые кодируют семантическое значение слов в плотные векторы.

Расстояние ОМУ измеряет различие между двумя текстовыми документами как минимальное расстояние, которое необходимо «пройти» встроенным словам одного документа, чтобы достичь встроенных слов другого документа.

Например:

введите описание изображения здесь Источник: документ «От вложения слов в расстояния до документов»

Пакет gensim имеет реализацию ОМУ .

Для вашей проблемы вы должны сравнить введенное предложение со всеми другими предложениями и вернуть предложение с наименьшим ОМУ.

Брайан Спиринг
источник
2

Вы можете попробовать простое решение, используя sklearn, и оно будет работать нормально.

  • Используйте tfidfvectorizer, чтобы получить векторное представление каждого текста

  • Установите векторизатор со своими данными, удалив стоп-слова.

  • Преобразование новой записи с ранее обученным векторизатором

  • Вычислите косинусное сходство между этим представлением и каждым представлением элементов в вашем наборе данных.

Если у вас есть огромный набор данных, вы можете кластеризовать его (например, используя KMeans из scikit learn) после получения представления и до прогнозирования новых данных.

Этот код выполняет все эти шаги. Вы можете проверить это на моем GitHub репо .

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 .
им удалось сжать семантическую, синтаксическую глобальную особенность предложения в некоторое скрытое пространство, выраженное, возможно, с помощью конечных 10-30 независимых случайных величин (факторизованное распределение).
Новая идея в этой работе, они интерполируют между двумя предложениями. и результаты были довольно удивительными.

Фади Бакура
источник
0

Обобщенное решение состоит из следующих шагов -

  1. Фичеризация или вложение слов в предложение.
  2. Применение метрики сходства между предложениями.

Для 1. word2vec - лучший выбор, но если вы не хотите использовать word2vec, вы можете сделать некоторые приближения к нему. Одним из способов является создание матрицы совпадений слов из ваших обученных предложений с последующим применением к ним ЦВД . Coccurance матрицаNИксN размерность при преобразовании в NИксd размерность, делает для векторов слова d Габаритные размеры.

Получив вложение слов каждого слова, вы можете применить к каждому предложению любую метрику сходства, например косинусное сходство и т. Д., Чтобы измерить сходство с другими.

Mr.Sigma.
источник