Previsão de similaridade de sentença

15

Estou procurando resolver o seguinte problema: Eu tenho um conjunto de frases como meu conjunto de dados e desejo poder digitar uma nova frase e encontrar a frase em que a nova é a mais semelhante no conjunto de dados. Um exemplo seria semelhante a:

Nova frase: " I opened a new mailbox"

Previsão com base no conjunto de dados:

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

Eu li que a semelhança de cosseno pode ser usada para resolver esses tipos de problemas associados ao tf-idf (e os RNNs não devem trazer melhorias significativas para os métodos básicos), ou também o word2vec é usado para problemas semelhantes. Também são realmente viáveis ​​para uso neste caso específico? Existem outras técnicas / algoritmos para resolver isso (de preferência com Python e SKLearn, mas também estou aberto para aprender sobre o TensorFlow)?

lte__
fonte
Definitivamente, verifique Bert . Aqui está uma boa implementação . Ele faz exatamente o que você está procurando, com resultados muito bons
GioGio 30/12/19

Respostas:

26

Seu problema pode ser resolvido com o Word2vec e também com o Doc2vec. O Doc2vec daria melhores resultados porque leva em consideração as sentenças durante o treinamento do modelo.

Solução Doc2vec
Você pode treinar seu modelo doc2vec seguindo este link . Você pode executar algumas etapas de pré-processamento, como remover todas as palavras de parada (palavras como "the", "an" etc.) que não agregam muito significado à frase. Depois de treinar seu modelo, você poderá encontrar frases semelhantes usando o código a seguir.

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

Os resultados acima são uma lista de tuplas para (label,cosine_similarity_score). Você pode mapear saídas para frases fazendo train[29670].

Observe que a abordagem acima só fornecerá bons resultados se o seu modelo doc2vec contiver incorporação de palavras encontradas na nova frase. Se você tentar obter semelhança com algumas frases sem sentido sdsf sdf f sdf sdfsdffg, ele fornecerá poucos resultados, mas essas podem não ser as frases semelhantes, já que seu modelo treinado pode não ter visto essas palavras sem sentido ao treinar o modelo. Portanto, tente treinar seu modelo no máximo de frases possível para incorporar o máximo de palavras para obter melhores resultados.

Solução Word2vec
Se você estiver usando o word2vec, precisará calcular o vetor médio para todas as palavras em cada frase e usar a semelhança de cosseno entre vetores.

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 semelhança

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
fonte
Obrigado! Isso funcionará no fim de semana, mas a solução parece perfeita à primeira vista. Parabéns!
Lte__ 25/17
precisamos tokenizar as sentenças para o treinamento
PYD
sim @pyd nós precisamos! sentence_1.split()faz o mesmo.
Harman
4

A Distância do motor de palavras (WMD) é um algoritmo para encontrar a distância entre as frases. O WMD é baseado em incorporação de palavras (por exemplo, word2vec), que codifica o significado semântico das palavras em vetores densos.

A distância WMD mede a diferença entre dois documentos de texto como a quantidade mínima de distância que as palavras incorporadas de um documento precisam "viajar" para alcançar as palavras incorporadas de outro documento.

Por exemplo:

insira a descrição da imagem aqui Fonte: Documento "De incorporados ao Word para documentar distâncias"

O pacote gensim possui uma implementação WMD .

Para o seu problema, você compararia a sentença inserida com todas as outras sentenças e retornaria a sentença com menor WMD.

Brian Spiering
fonte
2

Você pode tentar uma solução fácil usando o sklearn e isso funcionará bem.

  • Use tfidfvectorizer para obter uma representação vetorial de cada texto

  • Ajuste o vetorizador com seus dados, removendo palavras de parada.

  • Transforme a nova entrada com o vetorizador treinado anteriormente

  • Calcule a semelhança de cosseno entre essa representação e cada representação dos elementos em seu conjunto de dados.

Se você possui um conjunto de dados hugh, pode agrupá-lo (por exemplo, usando o KMeans do scikit learn) depois de obter a representação e antes de prever novos dados.

Este código executa todas essas etapas. Você pode verificá-la no meu 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
fonte
Ei, seria muito bom se você pudesse mostrar um exemplo de como usar a similitude cosseno?
Tido 22/01/19
Ei, a parte 2 não deve vir em primeiro lugar, caber em todos os dados e usá-la para transformar cada texto? Seria muito bom se você pudesse mostrar um exemplo do uso da similitude cosseno?
Tido 22/01/19
1

Há algum trabalho recente baseado no Auto-codificador variacional em modelos RNN. Gerando frases a partir de um espaço contínuo , com implementações pytorch: código do github .
eles conseguiram compactar o recurso global sintático e semântico de uma sentença em algum espaço latente expresso talvez com algumas variáveis ​​aleatórias independentes de 10 a 30 finitas (distribuição fatorada).
a nova idéia neste trabalho, eles interpolam entre duas frases. e os resultados foram surpreendentes.

Fadi Bakoura
fonte
0

A solução generalizada consiste nas seguintes etapas -

  1. Caracterização ou incorporação de palavras de uma frase.
  2. Aplicando uma métrica de similaridade entre frases.

Para 1. word2vec é a melhor escolha, mas se você não quiser usar o word2vec, poderá fazer algumas aproximações. Uma maneira é criar uma matriz de co-ocorrência de palavras a partir de suas frases treinadas, seguida pela aplicação do TSVD nela. Matriz de Coccurance denXn dimensionalidade quando convertido em nXd dimensionalidade, cria vetores de palavras de d dimensões.

Depois de obter a incorporação de palavras de cada palavra, você pode aplicar qualquer uma das métricas de similaridade, como similaridade de cosseno, etc. em cada frase para medir a similaridade com outras.

Mr.Sigma.
fonte