Satzähnlichkeitsvorhersage


15

Ich möchte das folgende Problem lösen: Ich habe eine Reihe von Sätzen als Datensatz, und ich möchte in der Lage sein, einen neuen Satz einzugeben und den Satz zu finden, der dem neuen Satz im Datensatz am ähnlichsten ist. Ein Beispiel würde so aussehen:

Neuer Satz: " I opened a new mailbox"

Vorhersage basierend auf Datensatz:

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

Ich habe gelesen, dass Cosinus-Ähnlichkeit verwendet werden kann, um diese Art von Problemen zusammen mit tf-idf zu lösen (und RNNs sollten keine signifikanten Verbesserungen der grundlegenden Methoden bringen), oder auch word2vec wird für ähnliche Probleme verwendet. Sind diese auch in diesem speziellen Fall tatsächlich einsetzbar? Gibt es andere Techniken / Algorithmen, um dies zu lösen (vorzugsweise mit Python und SKLearn, aber ich bin auch offen für Informationen zu TensorFlow)?


Überprüfen Sie auf jeden Fall Bert . Hier ist eine schöne Implementierung . Es macht genau das, was Sie suchen, mit ziemlich guten Ergebnissen
GioGio

Antworten:


25

Ihr Problem kann sowohl mit Word2vec als auch mit Doc2vec gelöst werden. Doc2vec würde bessere Ergebnisse liefern, da es beim Trainieren des Modells Sätze berücksichtigt.

Doc2vec-Lösung
Über diesen Link können Sie Ihr doc2vec-Modell trainieren . Möglicherweise möchten Sie einige Vorverarbeitungsschritte ausführen, z. B. das Entfernen aller Stoppwörter (Wörter wie "the", "an" usw., die dem Satz nicht viel Bedeutung verleihen). Sobald Sie Ihr Modell trainiert haben, können Sie die ähnlichen Sätze mit folgendem Code finden.

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)

Ergebnisse:

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

Die obigen Ergebnisse sind eine Liste von Tupeln für (label,cosine_similarity_score). Sie können die Ausgaben auf Sätze abbilden, indem Sie tun train[29670].

Bitte beachten Sie, dass der oben beschriebene Ansatz nur dann gute Ergebnisse liefert, wenn Ihr doc2vec-Modell Einbettungen für Wörter enthält, die im neuen Satz gefunden wurden. Wenn Sie versuchen, Ähnlichkeit für einen Kauderwelsch-Satz wie zu erhalten sdsf sdf f sdf sdfsdffg, erhalten Sie nur wenige Ergebnisse, aber dies sind möglicherweise nicht die tatsächlich ähnlichen Sätze, da Ihr trainiertes Modell diese Kauderwelsch-Wörter möglicherweise beim Trainieren des Modells nicht gesehen hat. Versuchen Sie also, Ihr Modell in so vielen Sätzen wie möglich zu trainieren, um so viele Wörter wie möglich zu integrieren, um bessere Ergebnisse zu erzielen.

Word2vec-Lösung
Wenn Sie word2vec verwenden, müssen Sie den Durchschnittsvektor für alle Wörter in jedem Satz berechnen und die Kosinusähnlichkeit zwischen den Vektoren verwenden.

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

Ähnlichkeit berechnen

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

Vielen Dank! Wird über das Wochenende daran arbeiten, aber die Lösung scheint auf den ersten Blick perfekt zu sein. Ein dickes Lob!
25.


ja @pyd müssen wir! sentence_1.split()macht das gleiche.
Harman

4

Word Mover's Distance (WMD) ist ein Algorithmus zum Ermitteln der Entfernung zwischen Sätzen. WMD basiert auf Worteinbettungen (z. B. word2vec), die die semantische Bedeutung von Wörtern in dichte Vektoren kodieren.

Der WMD-Abstand misst die Unähnlichkeit zwischen zwei Textdokumenten als den Mindestabstand, den die eingebetteten Wörter eines Dokuments "zurücklegen" müssen, um die eingebetteten Wörter eines anderen Dokuments zu erreichen.

Beispielsweise:

Bildbeschreibung hier eingeben Quelle: Papier "Von Word-Einbettungen zum Dokumentieren von Entfernungen"

Das gensim-Paket enthält eine WMD-Implementierung .

Für Ihr Problem würden Sie den eingegebenen Satz mit allen anderen Sätzen vergleichen und den Satz mit der niedrigsten WMD zurückgeben.


2

Mit sklearn können Sie eine einfache Lösung ausprobieren, die problemlos funktioniert.

  • Verwenden Sie tfidfvectorizer , um eine Vektordarstellung für jeden Text zu erhalten

  • Passen Sie den Vektorisierer an Ihre Daten an und entfernen Sie die Stoppwörter.

  • Transformieren Sie den neuen Eintrag mit dem zuvor trainierten Vektorisierer

  • Berechnen Sie die Kosinusähnlichkeit zwischen dieser Darstellung und jeder Darstellung der Elemente in Ihrem Datensatz.

Wenn Sie über einen umfangreichen Datensatz verfügen, können Sie ihn nach dem Abrufen der Darstellung und vor dem Vorhersagen neuer Daten gruppieren (z. B. mit KMeans von scikit learn).

Dieser Code führt alle diese Schritte aus. Sie können es auf meinem Github- Repo überprüfen .

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

Hey, wäre es wirklich schön, wenn Sie ein Beispiel für die Verwendung der Cosinus-Ähnlichkeit zeigen könnten?
Tido

Hey, sollte Teil 2 nicht an erster Stelle stehen, auf alle Daten passen und diese verwenden, um jeden Text zu transformieren? Es wäre wirklich schön, wenn Sie ein Beispiel für die Verwendung der Cosinus-Ähnlichkeit zeigen könnten.
Tido

1

Es gibt einige neuere Arbeiten, die auf Variational Auto-Encoder in RNN-Modellen basieren. Generieren von Sätzen aus einem fortlaufenden Raum mit Pytorch-Implementierungen: Github-Code .
es gelang ihnen, das semantische, syntaktische globale Merkmal eines Satzes in einen latenten Raum zu komprimieren, der möglicherweise mit einigen endlichen 10 bis 30 unabhängigen Zufallsvariablen ausgedrückt wird (faktorisierte Verteilung).
die neuartige Idee in dieser Arbeit, interpolieren sie zwischen zwei Sätzen. und die Ergebnisse waren ziemlich erstaunlich.


0

Die verallgemeinerte Lösung besteht aus den folgenden Schritten:

  1. Featurization oder Worteinbettungen eines Satzes.
  2. Anwenden einer Ähnlichkeitsmetrik zwischen Sätzen.

Für 1. ist word2vec die beste Wahl, aber wenn Sie word2vec nicht verwenden möchten, können Sie einige Annäherungen daran vornehmen. Eine Möglichkeit besteht darin, aus Ihren trainierten Sätzen eine Matrix von Wörtern zu erstellen , die gleichzeitig vorkommt , und TSVD darauf anzuwenden . Coccurance Matrix vonnXnnXdd

Sobald Sie die Worteinbettung für jedes Wort erhalten haben, können Sie eine der Ähnlichkeitsmetriken wie Cosinus-Ähnlichkeit usw. auf jeden Satz anwenden, um die Ähnlichkeit mit anderen zu messen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.