Prédiction de similarité de phrase

15

Je cherche à résoudre le problème suivant: j'ai un ensemble de phrases comme ensemble de données et je veux pouvoir taper une nouvelle phrase et trouver la phrase à laquelle la nouvelle est la plus similaire dans l'ensemble de données. Un exemple ressemblerait à:

Nouvelle phrase: " I opened a new mailbox"

Prédiction basée sur un ensemble de données:

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

J'ai lu que la similitude en cosinus peut être utilisée pour résoudre ces types de problèmes associés à tf-idf (et les RNN ne devraient pas apporter d'améliorations significatives aux méthodes de base), ou bien word2vec est utilisé pour des problèmes similaires. Ceux-ci sont-ils réellement viables dans ce cas spécifique également? Existe-t-il d'autres techniques / algorithmes pour résoudre ce problème (de préférence avec Python et SKLearn, mais je suis également ouvert à apprendre sur TensorFlow)?

lte__
la source
Vérifiez certainement Bert . Voici une belle implémentation . Il fait exactement ce que vous recherchez avec de très bons résultats
GioGio

Réponses:

26

Votre problème peut être résolu avec Word2vec ainsi que Doc2vec. Doc2vec donnerait de meilleurs résultats car il prend en compte les phrases lors de l'apprentissage du modèle.

Solution Doc2vec
Vous pouvez former votre modèle doc2vec en suivant ce lien . Vous voudrez peut-être effectuer certaines étapes de prétraitement comme la suppression de tous les mots vides (des mots comme "le", "un", etc. qui n'ajoutent pas beaucoup de sens à la phrase). Une fois que vous avez formé votre modèle, vous pouvez trouver les phrases similaires en utilisant le code suivant.

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)

Résultats:

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

Les résultats ci-dessus sont une liste de tuples pour (label,cosine_similarity_score). Vous pouvez mapper les sorties aux phrases en faisant train[29670].

Veuillez noter que l'approche ci-dessus ne donnera de bons résultats que si votre modèle doc2vec contient des incorporations pour les mots trouvés dans la nouvelle phrase. Si vous essayez d'obtenir une similitude pour certaines phrases de charabia comme sdsf sdf f sdf sdfsdffg, cela vous donnera peu de résultats, mais ce ne sont peut-être pas les phrases similaires réelles car votre modèle formé n'a peut-être pas vu ces mots de charabia lors de la formation du modèle. Essayez donc de former votre modèle sur autant de phrases que possible pour incorporer autant de mots pour de meilleurs résultats.

Solution Word2vec
Si vous utilisez word2vec, vous devez calculer le vecteur moyen pour tous les mots de chaque phrase et utiliser la similitude en cosinus entre les vecteurs.

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

Calculer la similitude

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
la source
Je vous remercie! Cela fonctionnera pendant le week-end, mais la solution semble parfaite à première vue. Gloire!
lte__
devons-nous symboliser les phrases pour la formation
pyd
oui @pyd nous devons! sentence_1.split()fait de même.
Harman
4

Word Mover's Distance (WMD) est un algorithme pour trouver la distance entre les phrases. WMD est basé sur des incorporations de mots (par exemple, word2vec) qui codent la signification sémantique des mots en vecteurs denses.

La distance WMD mesure la dissemblance entre deux documents texte comme la distance minimale que les mots incorporés d'un document doivent parcourir pour atteindre les mots incorporés d'un autre document.

Par exemple:

entrez la description de l'image ici Source: document "Des intégrations de mots aux distances des documents"

Le package gensim a une implémentation WMD .

Pour votre problème, vous devez comparer la phrase entrée à toutes les autres phrases et renvoyer la phrase qui a le plus d'ADM.

Brian Spiering
la source
2

Vous pouvez essayer une solution simple en utilisant sklearn et cela fonctionnera bien.

  • Utilisez tfidfvectorizer pour obtenir une représentation vectorielle de chaque texte

  • Adapter le vectoriseur à vos données, en supprimant les mots vides.

  • Transformez la nouvelle entrée avec le vectoriseur préalablement formé

  • Calculez la similitude en cosinus entre cette représentation et chaque représentation des éléments de votre ensemble de données.

Si vous avez un ensemble de données hugh, vous pouvez le regrouper (par exemple en utilisant KMeans de scikit learn) après avoir obtenu la représentation et avant de prédire de nouvelles données.

Ce code effectue toutes ces étapes. Vous pouvez le vérifier sur mon 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])
Federico Caccia
la source
Hé, ce serait vraiment bien si vous pouviez montrer un exemple d'utilisation de la similitude cosinus?
Tido
Hé, la partie 2 ne devrait-elle pas venir en premier, tenir sur toutes les données et l'utiliser pour transformer chaque texte? Ce serait vraiment bien si vous pouviez montrer un exemple d'utilisation de la similitude cosinus?
Tido
1

Il existe des travaux récents basés sur l'encodage automatique variationnel dans les modèles RNN.Génération de phrases à partir d'un espace continu , avec implémentations pytorch: code github .
ils ont réussi à compresser la caractéristique globale sémantique et syntaxique d'une phrase dans un espace latent exprimé peut-être avec quelques 10 à 30 variables aléatoires indépendantes finies (distribution factorisée).
l'idée nouvelle dans ce travail, ils interpolent entre deux phrases. et les résultats étaient assez étonnants.

Fadi Bakoura
la source
0

La solution généralisée comprend les étapes suivantes -

  1. Caractérisation ou intégration de mots d'une phrase.
  2. Appliquer une métrique de similitude entre les phrases.

Pour 1. word2vec est le meilleur choix mais si vous ne voulez pas utiliser word2vec, vous pouvez faire quelques approximations. Une façon consiste à créer une matrice de cooccurrence de mots à partir de vos phrases entraînées, puis à y appliquer TSVD . Matrice de coccurance denXn dimensionnalité lors de la conversion en nX dimensionnalité, fait des vecteurs de mots de dimensions.

Une fois que vous avez incorporé le mot de chaque mot, vous pouvez appliquer n'importe quelle métrique de similitude comme la similitude en cosinus, etc. sur chaque phrase pour mesurer la similitude avec les autres.

Mr.Sigma.
la source