Il existe un moyen d'utiliser Doc2Vec, etc. pour calculer la similitude entre les phrases, mais c'est un peu gênant car je dois créer un modèle pour cela à partir de zéro. Il peut être plus polyvalent et plus facile d'utiliser le modèle Word2Vec tel quel si vous ne souhaitez obtenir qu'un certain degré de précision.
J'ai donc calculé la similitude entre les phrases en fonction de la moyenne des vecteurs de caractéristiques des mots contenus dans la phrase et de la similitude cosinus entre les phrases.
# OS
macOS Sierra
# Python(Utilisez 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)
Cela ne fonctionnait pas bien avec python3.6, donc la version python3.5 d'Anaconda ([Anaconda 4.2.0 pour python3](https://repo.continuum.io/archive/Anaconda3-4.2.0-MacOSX-x86_64] .pkg)) est utilisé.
Il a fallu trop de temps à mon MacBook Air pour générer un dictionnaire à partir du corpus
Le modèle entraîné de fastText a été publié
Nous avons utilisé un modèle entraîné plus publié. Cette fois, nous utiliserons un modèle (model_neologd.vec) dans lequel le texte de Wikipedia est divisé en utilisant NEologd de MeCab et entraîné par fastText. (Nombre de dimensions: 300)
import gensim
word2vec_model = gensim.models.KeyedVectors.load_word2vec_format('model/model_neologd.vec', binary=False)
(Étant donné que le fichier est proche de 1 Go, sa lecture prend des dizaines de secondes)
En utilisant ce modèle, vous pouvez effectuer un calcul sémantique de mots à l'aide de vecteurs de caractéristiques.
import pprint
pprint.pprint(word2vec_model.most_similar(positive=['femme', 'Roi'], negative=['Homme']))
# => [('Reine', 0.7062159180641174),
# ('Royal', 0.6530475616455078),
# ('Royal', 0.6122198104858398),
# ('Prince', 0.6098779439926147),
# ('famille royale', 0.6084121465682983),
# ('Princesse', 0.6005773544311523),
# ('Reine', 0.5964134335517883),
# ('Roi', 0.593998908996582),
# ('Monsieur', 0.5929002165794373),
# ('Palais Royal', 0.5772185325622559)]
#Si vous souhaitez calculer la similitude entre des mots simples, modélisez.Peut être calculé par similitude
pprint.pprint(word2vec_model.similarity('Roi', 'Reine'))
# => 0.74155587641044496
pprint.pprint(word2vec_model.similarity('Roi', 'ramen'))
# => 0.036460763469822188
D'une certaine manière, le résultat est comme ça.
Utilisez MeCab pour décomposer le langage naturel en notes séparées. Spécifiez mecab-ipadic-neologd, qui est également utilisé pour générer des modèles entraînés sous forme de dictionnaire, et spécifiez la sortie sous forme de division.
import MeCab
mecab = MeCab.Tagger("-d /usr/local/lib/mecab/dic/mecab-ipadic-neologd -Owakati")
mecab.parse("Il s'est cassé l'estomac hier")
# => 'Il s'est cassé l'estomac hier\n'
Le texte séparé est séparé par des espaces. Le saut de ligne étant inclus à la fin, il semble nécessaire de le supprimer au moment de la mise en œuvre. (Au fait, MeCab a été installé en utilisant mecab-python3. Il semble que cela ne fonctionne pas correctement avec la série python3.6, j'ai donc dû utiliser la série python3.5 à 2017/5)
Dans cette méthode, la moyenne des vecteurs de caractéristiques des mots utilisés dans la phrase est utilisée comme vecteur de caractéristiques de la phrase elle-même, donc une fonction pour cela est définie.
import numpy as np
def avg_feature_vector(sentence, model, num_features):
words = mecab.parse(sentence).replace(' \n', '').split() #Ligne de rupture à la fin du mecab(\n)Est une sortie, alors supprimez-la
feature_vec = np.zeros((num_features,), dtype="float32") #Initialiser le conteneur de vecteurs de fonctionnalités
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
Il s'agit simplement de faire la moyenne des vecteurs de caractéristiques pour chaque mot. (Étant donné que le nombre de dimensions du modèle entraîné est de 300, spécifiez 300 pour num_features)
avg_feature_vector("Il s'est cassé l'estomac hier", 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)
Une fois exécuté, je pense qu'une quantité de caractéristiques de 300 dimensions sera sortie.
Ensuite, la fonction ci-dessus est utilisée pour calculer la similitude cosinus du vecteur moyen entre deux phrases.
from scipy import spatial
def sentence_similarity(sentence_1, sentence_2):
#Le modèle Word2Vec utilisé cette fois est généré avec un vecteur de caractéristiques de 300 dimensions, donc num_caractéristiques également spécifiées comme 300
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)
#Calculer la similitude cosinus en soustrayant la distance entre les vecteurs de 1
return 1 - spatial.distance.cosine(sentence_1_avg_vector, sentence_2_avg_vector)
En utilisant cette fonction, vous pouvez facilement calculer la similitude entre les phrases. (La plage est de 0 à 1, et plus elle est proche de 1, plus elle est similaire.)
result = sentence_similarity(
"Il a mangé un ramen épicé hier et a eu faim",
"Hier, j'ai mangé une cuisine chinoise épicée et j'ai eu faim"
)
print(result)
# => 0.973996032475
result = sentence_similarity(
"Ce n'est pas bon ... je dois faire quelque chose rapidement ...",
"Nous fournirons des informations d'emploi soigneusement sélectionnées"
)
print(result)
# => 0.608137464334
J'ai pu calculer une valeur numérique comme ça!
** Dans le cas de phrases longues, le degré de similitude est élevé. ** ** Puisque seule la moyenne des mots est prise et comparée, il devient difficile de faire une différence dans la valeur moyenne entre les phrases dans une longue phrase, et la similitude devient élevée même dans les phrases sans rapport.
result = sentence_similarity(
"C'est enfin dans l'histoire de cette histoire. J'ai peur que d'autres en viennent au point où ils ne devraient pas avancer, et je m'en contente dans une certaine mesure.",
"Même si je suis malade, c'est une bonne journée. En pensant à Gauche comme à une souris, votre visage a pressé le soupir de Doremifa et le prochain violoncelle de renard, et la différence entre eux est assez différente."
)
print(result)
# => 0.878950984671
Même si cela peut être fait, la comparaison entre des phrases de 10 mots est la limite.
** Impossible de gérer les mots inconnus. ** ** Puisqu'il n'est pas possible de sortir un vecteur de caractéristiques pour un mot inconnu qui n'est pas enregistré dans le modèle entraîné, il semble nécessaire de prendre des mesures telles que le remplissage du mot lui-même avec le vecteur de caractéristiques moyen des autres mots. (Cependant, dans ce cas, les mots inconnus ont souvent des caractéristiques sémantiques, ce qui réduit la précision de la similitude.)
>>> result = sentence_similarity(
... "L'adoption par référence est devenue populaire ces dernières années",
... "L'ère du recrutement par lots de nouveaux diplômés est révolue"
... )
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 'Référence' not in vocabulary"
Dans ce cas, je ne trouve pas le mot référence et il me manque.
La méthode elle-même étant simple, je pense que les cas qui peuvent être utilisés sont assez limités. Au contraire, s'il ne faut traiter que des phrases courtes, il semble que cette méthode puisse également apporter une certaine précision. Lors de la recherche sérieuse de la similitude entre les phrases, c'est une approche simple d'utiliser une méthode comme Doc2Vec, de préparer un corpus qui convient à l'objectif du modèle lui-même et de créer le vôtre. ..
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")
#Calculer la moyenne des vecteurs de caractéristiques des mots utilisés dans la phrase
def avg_feature_vector(sentence, model, num_features):
words = mecab.parse(sentence).replace(' \n', '').split() #Ligne de rupture à la fin du mecab(\n)Est une sortie, alors supprimez-la
feature_vec = np.zeros((num_features,), dtype="float32") #Initialiser le conteneur de vecteurs de fonctionnalités
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
#Calculez la similitude entre deux phrases
def sentence_similarity(sentence_1, sentence_2):
#Le modèle Word2Vec utilisé cette fois est généré avec un vecteur de caractéristiques de 300 dimensions, donc num_caractéristiques également spécifiées comme 300
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)
#Calculer la similitude cosinus en soustrayant la distance entre les vecteurs de 1
return 1 - spatial.distance.cosine(sentence_1_avg_vector, sentence_2_avg_vector)
result = sentence_similarity(
"Il a mangé un ramen épicé hier et a eu faim",
"Hier, j'ai mangé une cuisine chinoise épicée et j'ai eu faim"
)
print(result)
# => 0.973996032475
Recommended Posts