[PYTHON] Berechnung der Ähnlichkeit zwischen Sätzen mit Word2Vec (vereinfachte Version)

Es gibt eine Möglichkeit, Doc2Vec usw. zu verwenden, um die Ähnlichkeit zwischen Sätzen zu berechnen, aber es ist ein wenig mühsam, weil ich ein Modell dafür von Grund auf neu erstellen muss. Es ist möglicherweise vielseitiger und einfacher, das Word2Vec-Modell zu verwenden, als wenn Sie nur ein bestimmtes Maß an Genauigkeit erreichen möchten.

Also berechnete ich die Ähnlichkeit zwischen Sätzen basierend auf dem Merkmalsvektor-Durchschnitt der im Satz enthaltenen Wörter und der Kosinus-Ähnlichkeit zwischen Sätzen.

Umgebung

# OS
macOS Sierra

# Python(Verwenden Sie Anaconda)
Python : Python 3.5.3 :: Anaconda custom (x86_64)
pip : 9.0.1 from /Users/username/anaconda/lib/python3.5/site-packages (python 3.5)

Es funktionierte nicht gut mit Python3.6, also Python3.5-Version von Anaconda ([Anaconda 4.2.0 für Python3]) (https://repo.continuum.io/archive/Anaconda3-4.2.0-MacOSX-x86_64] .pkg)) wird verwendet.

Get & Load trainiertes Modell

Es hat zu lange gedauert, bis mein MacBook Air ein Wörterbuch aus dem Korpus erstellt hat

Das trainierte Modell von fastText wurde veröffentlicht

Wir haben ein veröffentlichtes trainiertes Modell verwendet. Dieses Mal verwenden wir ein Modell (model_neologd.vec), in dem der Text von Wikipedia mit NEologd von MeCab unterteilt und von fastText trainiert wird. (Anzahl der Dimensionen: 300)

Geladenes trainiertes Modell laden

import gensim
word2vec_model = gensim.models.KeyedVectors.load_word2vec_format('model/model_neologd.vec', binary=False)

(Da die Datei fast 1 GB groß ist, dauert das Lesen mehrere zehn Sekunden.)

Mit diesem Modell können Sie eine semantische Berechnung von Wörtern mithilfe von Merkmalsvektoren durchführen.

Wortberechnung mit Word2Vec (Beispiel: Frau + König-Mann)

import pprint
pprint.pprint(word2vec_model.most_similar(positive=['Frau', 'König'], negative=['Mann']))

# => [('Königin', 0.7062159180641174),
# ('königlich', 0.6530475616455078),
# ('königlich', 0.6122198104858398),
# ('Prinz', 0.6098779439926147),
# ('königliche Familie', 0.6084121465682983),
# ('Prinzessin', 0.6005773544311523),
# ('Königin', 0.5964134335517883),
# ('König', 0.593998908996582),
# ('Herr', 0.5929002165794373),
# ('Königlicher Palast', 0.5772185325622559)]

Berechnung der Ähnlichkeit zwischen Wörtern durch Word2Vec

#Wenn Sie die Ähnlichkeit zwischen einfachen Wörtern berechnen möchten, modellieren Sie.Kann durch Ähnlichkeit berechnet werden
pprint.pprint(word2vec_model.similarity('König', 'Königin'))
# => 0.74155587641044496
pprint.pprint(word2vec_model.similarity('König', 'Ramen'))
# => 0.036460763469822188

Irgendwie ist das Ergebnis so.

Laden Sie MeCab

Verwenden Sie MeCab, um die natürliche Sprache in separate Notizen zu zerlegen. Geben Sie mecab-ipadic-neologd an, mit dem auch trainierte Modelle als Wörterbuch generiert werden, und geben Sie die Ausgabe in Form einer Division an.

import MeCab
mecab = MeCab.Tagger("-d /usr/local/lib/mecab/dic/mecab-ipadic-neologd -Owakati")

mecab.parse("Er hat gestern Hunger bekommen")
# => 'Er hat sich gestern den Bauch gebrochen\n'

Der getrennte Text wird durch Leerzeichen getrennt. Da der Zeilenumbruch am Ende enthalten ist, muss er zum Zeitpunkt der Implementierung gelöscht werden. (MeCab wurde übrigens mit mecab-python3 installiert. Es scheint, dass es mit der python3.6-Serie nicht richtig funktioniert, daher musste ich 2017/5 die python3.5-Serie verwenden.)

Berechnen Sie den Durchschnitt der Merkmalsvektoren der im Satz verwendeten Wörter

Bei diesem Verfahren wird der Merkmalsvektormittelwert der im Satz verwendeten Wörter als Merkmalsvektor des Satzes selbst verwendet, so dass eine Funktion dafür definiert wird.

import numpy as np
def avg_feature_vector(sentence, model, num_features):
    words = mecab.parse(sentence).replace(' \n', '').split() #Unterbrechen Sie die Linie am Ende des Mecab(\n)Wird ausgegeben, also entfernen Sie es
    feature_vec = np.zeros((num_features,), dtype="float32") #Feature-Vektor-Container initialisieren
    for word in words:
        feature_vec = np.add(feature_vec, model[word])
    if len(words) > 0:
        feature_vec = np.divide(feature_vec, len(words))
    return feature_vec

Es werden nur die Merkmalsvektoren für jedes Wort gemittelt. (Da die Anzahl der Dimensionen des trainierten Modells 300 beträgt, geben Sie 300 für num_features an.)

avg_feature_vector("Er hat gestern Hunger bekommen", word2vec_model, 300)
# => array([  6.39975071e-03,  -6.38077855e-02,  -1.41418248e-01,
#       -2.01289997e-01,   1.76049918e-01,   1.99666247e-02,
#             :                 :                 :
#       -7.54096806e-02,  -5.46530560e-02,  -9.14395228e-02,
#       -2.21335635e-01,   3.34903784e-02,   1.81226760e-01], dtype=float32)

Bei der Ausführung denke ich, dass eine 300-dimensionale Merkmalsmenge ausgegeben wird.

Berechnen Sie die Ähnlichkeit zwischen zwei Sätzen

Verwenden Sie als Nächstes die obige Funktion, um die Kosinusähnlichkeit des Durchschnittsvektors zwischen den beiden Sätzen zu berechnen.

from scipy import spatial
def sentence_similarity(sentence_1, sentence_2):
    #Das diesmal verwendete Word2Vec-Modell wird mit einem 300-dimensionalen Merkmalsvektor generiert, also num_Funktionen auch als 300 angegeben
    num_features=300
    sentence_1_avg_vector = avg_feature_vector(sentence_1, word2vec_model, num_features)
    sentence_2_avg_vector = avg_feature_vector(sentence_2, word2vec_model, num_features)
    #Berechnen Sie die Kosinusähnlichkeit, indem Sie den Abstand zwischen Vektoren von 1 subtrahieren
    return 1 - spatial.distance.cosine(sentence_1_avg_vector, sentence_2_avg_vector)

Mit dieser Funktion können Sie die Ähnlichkeit zwischen Sätzen leicht berechnen. (Der Bereich liegt zwischen 0 und 1, und je näher er an 1 liegt, desto ähnlicher ist er.)

result = sentence_similarity(
    "Er hat gestern ein scharfes Ramen gegessen und ist hungrig geworden",
    "Gestern habe ich ein scharfes chinesisches Essen gegessen und bin hungrig geworden"
)
print(result)
# =>  0.973996032475

result = sentence_similarity(
    "Es ist nicht gut ... Ich muss schnell etwas tun ...",
    "Wir liefern sorgfältig ausgewählte Auftragsinformationen"
)
print(result)
# => 0.608137464334

Ich konnte so einen numerischen Wert berechnen!

Problem der Methode ①

** Bei langen Sätzen ist der Ähnlichkeitsgrad hoch. ** ** ** Da nur der Durchschnitt der Wörter genommen und verglichen wird, wird es schwierig, den Durchschnittswert zwischen Sätzen in einem langen Satz zu unterscheiden, und die Ähnlichkeit wird selbst in nicht verwandten Sätzen hoch.

result = sentence_similarity(
    "Es ist endlich in der Geschichte dieser Geschichte. Endlich würden andere Pädagogen an einen Punkt kommen, an dem sie nicht vorantreiben sollten, aber ich bin sicher, dass sie missverstanden werden, und ich bin bis zu einem gewissen Grad damit zufrieden.",
    "Auch wenn ich krank bin, ist es ein guter Tag. Wenn Sie an Gauche als Maus denken, nippte Ihr Gesicht an dem Seufzer der Doremifa und dem nächsten Fuchscello, und der Unterschied zwischen ihnen ist ganz anders."
)
print(result)
# => 0.878950984671

Selbst wenn dies möglich ist, ist der Vergleich zwischen Sätzen mit 10 Wörtern die Grenze.

Problem der Methode ②

** Kann nicht mit unbekannten Wörtern umgehen. ** ** ** Da es nicht möglich ist, einen Merkmalsvektor für ein unbekanntes Wort auszugeben, das nicht im trainierten Modell registriert ist, erscheint es notwendig, Maßnahmen zu ergreifen, beispielsweise das Wort selbst mit dem durchschnittlichen Merkmalsvektor anderer Wörter zu füllen. (In diesem Fall weisen unbekannte Wörter jedoch häufig semantische Merkmale auf, was die Genauigkeit der Ähnlichkeit verringert.)

>>> result = sentence_similarity(
...     "Die Annahme von Empfehlungen ist in den letzten Jahren populär geworden",
...     "Die Ära der Batch-Rekrutierung neuer Absolventen ist vorbei"
... )
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
  File "<stdin>", line 5, in sentence_similarity
  File "<stdin>", line 6, in avg_feature_vector
  File "/Users/username/anaconda/lib/python3.5/site-packages/gensim/models/keyedvectors.py", line 574, in __getitem__
    return self.word_vec(words)
  File "/Users/username/anaconda/lib/python3.5/site-packages/gensim/models/keyedvectors.py", line 273, in word_vec
    raise KeyError("word '%s' not in vocabulary" % word)
KeyError: "word 'Verweisung' not in vocabulary"

In diesem Fall kann ich das Wort "Überweisung" nicht finden und es fehlt mir.

Zusammenfassung

Da die Methode selbst einfach ist, denke ich, dass die Fälle, die verwendet werden können, ziemlich begrenzt sind. Im Gegenteil, wenn es nur notwendig ist, mit kurzen Sätzen umzugehen, scheint es, dass diese Methode auch eine gewisse Genauigkeit liefern kann. Ist es nicht ein einfacher Ansatz, eine Methode wie Doc2Vec zu verwenden, um die Ähnlichkeit zwischen Sätzen ernsthaft zu finden und einen Korpus zu erstellen, der dem Zweck des Modells selbst entspricht? ..

Code im Artikel eingeführt (alle)

import gensim
import MeCab
import numpy as np
from scipy import spatial

word2vec_model = gensim.models.KeyedVectors.load_word2vec_format('model/model_neologd.vec', binary=False)
mecab = MeCab.Tagger("-d /usr/local/lib/mecab/dic/mecab-ipadic-neologd -Owakati")

#Berechnen Sie den Durchschnitt der Merkmalsvektoren der im Satz verwendeten Wörter
def avg_feature_vector(sentence, model, num_features):
    words = mecab.parse(sentence).replace(' \n', '').split() #Unterbrechen Sie die Linie am Ende des Mecab(\n)Wird ausgegeben, also entfernen Sie es
    feature_vec = np.zeros((num_features,), dtype="float32") #Feature-Vektor-Container initialisieren
    for word in words:
        feature_vec = np.add(feature_vec, model[word])
    if len(words) > 0:
        feature_vec = np.divide(feature_vec, len(words))
    return feature_vec

#Berechnen Sie die Ähnlichkeit zwischen zwei Sätzen
def sentence_similarity(sentence_1, sentence_2):
    #Das diesmal verwendete Word2Vec-Modell wird mit einem 300-dimensionalen Merkmalsvektor generiert, also num_Funktionen auch als 300 angegeben
    num_features=300
    sentence_1_avg_vector = avg_feature_vector(sentence_1, word2vec_model, num_features)
    sentence_2_avg_vector = avg_feature_vector(sentence_2, word2vec_model, num_features)
    #Berechnen Sie die Kosinusähnlichkeit, indem Sie den Abstand zwischen Vektoren von 1 subtrahieren
    return 1 - spatial.distance.cosine(sentence_1_avg_vector, sentence_2_avg_vector)

result = sentence_similarity(
    "Er hat gestern ein scharfes Ramen gegessen und ist hungrig geworden",
    "Gestern habe ich ein scharfes chinesisches Essen gegessen und bin hungrig geworden"
)
print(result)
# => 0.973996032475

Referenz

Recommended Posts

Berechnung der Ähnlichkeit zwischen Sätzen mit Word2Vec (vereinfachte Version)
Berechnen Sie die Ähnlichkeit zwischen Sätzen mit Doc2Vec, einer Weiterentwicklung von Word2Vec
Ähnlichkeitsberechnung zwischen präzisen Episoden unter Verwendung der Live-Timeline und des Themenmodells
Berechnung der Ähnlichkeit durch MinHash
Berechnung des Normalenvektors mittels Faltung
[Python] Berechnung der Bildähnlichkeit (Würfelkoeffizient)
[Japanische Version] Beurteilung der Wortähnlichkeit für Polynomwörter mit ELMo und BERT
Berechnung der Support Vector Machine (SVM) (mit cvxopt)