Prognozowanie podobieństwa zdań


15

Szukam rozwiązania następującego problemu: Mam zestaw zdań jako zestaw danych i chcę móc wpisać nowe zdanie i znaleźć zdanie, które jest najbardziej podobne do tego w zestawie danych. Przykład mógłby wyglądać następująco:

Nowe zdanie: „ I opened a new mailbox

Prognozowanie na podstawie zestawu danych:

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

Czytałem, że podobieństwo cosinus może być użyte do rozwiązania tego rodzaju problemów w połączeniu z tf-idf (i RNN nie powinny przynosić znaczących ulepszeń w podstawowych metodach), lub też word2vec jest używany do podobnych problemów. Czy te rzeczywiście są również przydatne w tym konkretnym przypadku? Czy są jakieś inne techniki / algorytmy, aby rozwiązać ten problem (najlepiej w Pythonie i SKLearn, ale jestem otwarty na naukę o TensorFlow)?


Zdecydowanie sprawdź Bert . Oto niezła implementacja . Robi dokładnie to, czego szukasz, z całkiem dobrymi wynikami
GioGio,

Odpowiedzi:


26

Twój problem można rozwiązać za pomocą Word2vec oraz Doc2vec. Doc2vec dałby lepsze wyniki, ponieważ bierze pod uwagę zdania podczas szkolenia modelu.

Rozwiązanie Doc2vec
Możesz trenować swój model doc2vec, klikając ten link . Możesz wykonać kilka czynności wstępnego przetwarzania, takich jak usunięcie wszystkich słów stop (słowa takie jak „the”, „an” itp., Które nie dodają większego znaczenia do zdania). Po wytrenowaniu modelu możesz znaleźć podobne zdania, używając następującego kodu.

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)

Wyniki:

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

Powyższe wyniki to lista krotek dla (label,cosine_similarity_score). W ten sposób możesz odwzorować wyniki na zdania train[29670].

Należy pamiętać, że powyższe podejście da dobre wyniki tylko wtedy, gdy model doc2vec zawiera osadzenia słów znalezionych w nowym zdaniu. Jeśli spróbujesz uzyskać podobieństwo do jakiegoś bełkotliwego zdania sdsf sdf f sdf sdfsdffg, to da ci to niewiele rezultatów, ale mogą one nie być rzeczywistymi podobnymi zdaniami, ponieważ Twój wytrenowany model mógł nie widzieć tych bełkotliwych słów podczas treningu modelu. Spróbuj więc wytrenować swój model na jak największej liczbie zdań, aby uwzględnić jak najwięcej słów w celu uzyskania lepszych wyników.

Rozwiązanie Word2vec
Jeśli używasz word2vec, musisz obliczyć średni wektor dla wszystkich słów w każdym zdaniu i użyć podobieństwa cosinus między wektorami.

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

Oblicz podobieństwo

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)

Dziękuję Ci! Będzie to działać przez weekend, ale na pierwszy rzut oka rozwiązanie wydaje się idealne. Sława!
lte__

czy musimy
tokenizować

tak @pyd musimy! sentence_1.split()robi to samo.
Harman

4

Word Mover's Distance (WMD) to algorytm służący do określania odległości między zdaniami. WMD opiera się na osadzaniu słów (np. Word2vec), które kodują znaczenie semantyczne słów w gęstych wektorach.

Odległość WMD mierzy podobieństwo między dwoma dokumentami tekstowymi jako minimalną odległość, jaką muszą osadzić słowa osadzone w jednym dokumencie, aby dotrzeć do słów osadzonych w innym dokumencie.

Na przykład:

wprowadź opis zdjęcia tutaj Źródło: Papier „Od osadzania słów do odległości dokumentów”

Pakiet gensim ma wdrożenie BMR .

W przypadku twojego problemu porównasz wprowadzone zdanie ze wszystkimi innymi zdaniami i zwrócisz zdanie o najniższej BMR.


2

Możesz wypróbować proste rozwiązanie za pomocą sklearn i będzie działać dobrze.

  • Użyj tfidfvectorizer, aby uzyskać wektorową reprezentację każdego tekstu

  • Dopasuj wektoryzator do swoich danych, usuwając słowa-stop.

  • Przekształć nowy wpis z uprzednio przeszkolonym wektoryzatorem

  • Oblicz podobieństwo cosinus między tą reprezentacją a każdą reprezentacją elementów w zestawie danych.

Jeśli masz zestaw danych Hugh, możesz go zgrupować (na przykład za pomocą KMeans ze scikit learn) po uzyskaniu reprezentacji i przed prognozowaniem nowych danych.

Ten kod wykonuje wszystkie te kroki. Możesz to sprawdzić na moim repozytorium 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])

Hej, byłoby naprawdę miło, gdybyś mógł pokazać przykład użycia cosinusu similiairity?
Tido

Hej, czy część 2 nie powinna być na pierwszym miejscu, dopasowana do wszystkich danych i wykorzystana do przekształcenia każdego tekstu? Byłoby naprawdę miło, gdybyś mógł pokazać przykład użycia cosinusu similiairity?
Tido

1

Istnieje kilka ostatnich prac opartych na wariacyjnym auto-enkoderze w modelach RNN. Generowanie zdań z przestrzeni ciągłej z implementacjami pytorch: kod github .
Udało im się skompresować semantyczną, składniową globalną cechę zdania do jakiejś utajonej przestrzeni wyrażonej być może za pomocą skończonych 10–30 niezależnych zmiennych losowych (rozkład czynnikowy).
nowy pomysł w tej pracy interpolują dwa zdania. a wyniki były dość niesamowite.


0

Uogólnione rozwiązanie składa się z następujących kroków -

  1. Featuryzacja lub osadzanie słów w zdaniu.
  2. Zastosowanie wskaźnika podobieństwa między zdaniami.

nXnnXdd

Po osadzeniu słowa w każdym słowie możesz zastosować dowolną metrykę podobieństwa, taką jak podobieństwo cosinus itp. Do każdego zdania, aby zmierzyć podobieństwo z innymi.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.