Predicción de similitud de oraciones

15

Estoy tratando de resolver el siguiente problema: tengo un conjunto de oraciones como mi conjunto de datos, y quiero poder escribir una nueva oración y encontrar la oración con la que la nueva es más similar en el conjunto de datos. Un ejemplo se vería así:

Nueva oración: " I opened a new mailbox"

Predicción basada en el conjunto de datos:

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

He leído que la similitud de coseno se puede usar para resolver este tipo de problemas emparejados con tf-idf (y los RNN no deberían aportar mejoras significativas a los métodos básicos), o también se usa word2vec para problemas similares. ¿Son realmente viables para su uso en este caso específico también? ¿Existen otras técnicas / algoritmos para resolver esto (preferiblemente con Python y SKLearn, pero también estoy abierto a aprender sobre TensorFlow)?

lte__
fuente
Definitivamente revisa a Bert . Aquí hay una buena implementación . Hace exactamente lo que estás buscando con muy buenos resultados
GioGio

Respuestas:

26

Su problema se puede resolver con Word2vec y Doc2vec. Doc2vec daría mejores resultados porque toma en cuenta las oraciones al entrenar el modelo.

Solución Doc2vec
Puede entrenar su modelo doc2vec siguiendo este enlace . Es posible que desee realizar algunos pasos de preprocesamiento, como eliminar todas las palabras de detención (palabras como "the", "an", etc. que no agregan mucho significado a la oración). Una vez que haya entrenado su modelo, puede encontrar oraciones similares usando el siguiente código.

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)

Resultados:

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

Los resultados anteriores son una lista de tuplas para (label,cosine_similarity_score). Puede asignar salidas a oraciones haciendo train[29670].

Tenga en cuenta que el enfoque anterior solo dará buenos resultados si su modelo doc2vec contiene incrustaciones para las palabras que se encuentran en la nueva oración. Si trata de obtener similitud para alguna oración de galimatías sdsf sdf f sdf sdfsdffg, le dará pocos resultados, pero esas podrían no ser las oraciones similares reales ya que su modelo entrenado puede no haber visto estas palabras de galimatías mientras entrenaba el modelo. Así que trate de entrenar a su modelo en tantas oraciones como sea posible para incorporar tantas palabras para obtener mejores resultados.

Solución de Word2vec
Si está usando word2vec, necesita calcular el vector promedio para todas las palabras en cada oración y usar la similitud de coseno entre vectores.

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

Calcular similitud

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
fuente
¡Gracias! Trabajará en esto durante el fin de semana, pero la solución parece perfecta a primera vista. ¡Prestigio!
lte__
¿necesitamos tokenize las frases para la formación
PYD
sí @pyd tenemos que hacerlo! sentence_1.split()hace lo mismo
Harman
4

Word Mover's Distance (WMD) es un algoritmo para encontrar la distancia entre oraciones. WMD se basa en incrustaciones de palabras (por ejemplo, word2vec) que codifican el significado semántico de las palabras en vectores densos.

La distancia WMD mide la diferencia entre dos documentos de texto como la cantidad mínima de distancia que las palabras incrustadas de un documento necesitan "viajar" para llegar a las palabras incrustadas de otro documento.

Por ejemplo:

ingrese la descripción de la imagen aquí Fuente: Documento "De incrustaciones de palabras a distancias de documentos"

El paquete gensim tiene una implementación de ADM .

Para su problema, compararía la oración ingresada con todas las otras oraciones y devolvería la oración que tenga las ADM más bajas.

Brian Spiering
fuente
2

Puede probar una solución fácil usando sklearn y funcionará bien.

  • Use tfidfvectorizer para obtener una representación vectorial de cada texto

  • Ajuste el vectorizador con sus datos, eliminando palabras de detención.

  • Transforme la nueva entrada con el vectorizador previamente entrenado

  • Calcule la similitud de coseno entre esta representación y cada representación de los elementos en su conjunto de datos.

Si tiene un conjunto de datos hugh, puede agruparlo (por ejemplo, utilizando KMeans de scikit learn) después de obtener la representación y antes de predecir nuevos datos.

Este código realiza todos estos pasos. Puedes consultarlo en mi repositorio de 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])
Federico Caccia
fuente
Oye, ¿sería realmente bueno si pudieras mostrar un ejemplo del uso de la similitud del coseno?
Tido
Oye, ¿no debería ser la parte 2 lo primero, ajustarse a todos los datos y usar esto para transformar cada texto? ¿Sería realmente bueno si pudieras mostrar un ejemplo del uso de la similitud del coseno?
Tido
1

Hay algunos trabajos recientes basados ​​en el codificador automático variable en modelos RNN. Generando oraciones desde un espacio continuo , con implementaciones de pytorch : código github .
lograron comprimir la característica semántica y sintáctica global de una oración en un espacio latente expresado quizás con algunas variables aleatorias finitas independientes de 10 a 30 (distribución factorizada).
La idea novedosa en este trabajo, se interpolan entre dos oraciones. y los resultados fueron bastante sorprendentes.

Fadi Bakoura
fuente
0

La solución generalizada consta de los siguientes pasos:

  1. Emplazamiento o incrustaciones de palabras de una oración.
  2. Aplicando una métrica de similitud entre oraciones.

norteXnortenorteXre dimensionalidad, hace vectores de palabras de re dimensiones.

Una vez que consigues la inserción de palabras de cada palabra, puedes aplicar cualquiera de las métricas de similitud como coseno, etc. en cada oración para medir la similitud con otras.

Sr. Sigma.
fuente