Algorithme de recherche utilisant word2vec [python]

Aperçu

J'ai créé un algorithme de recherche en utilisant word2vec avec l'espoir que non seulement les mots exacts, mais aussi les synonymes seront atteints. En conséquence, les informations word2vec seules n'étaient pas satisfaisantes, mais il semble que l'effet attendu sera atteint, j'ai donc pensé qu'il serait utile de les combiner avec d'autres méthodes.

environnement

macOS Catalina 10.15.4 python 3.8.0

Apprentissage de word2vec

Je laisserai la méthode détaillée à d'autres articles. J'ai téléchargé le texte intégral de wikipedia, je l'ai partagé avec mecab-ipadic-neologd et j'ai appris word2vec avec gensim. Le code au moment de l'apprentissage est le suivant. J'ai emprunté le code à Création d'un modèle word2vec en utilisant le corpus Wikipedia | Journal de dévotion adhésif.

from gensim.models import word2vec
import logging

logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
sentences = word2vec.Text8Corpus('./wiki_wakati_neologd.txt')

model = word2vec.Word2Vec(sentences, size=200, min_count=20, window=15)
model.save("./wiki_neologd.model")

Algorithme de recherche

Calculez la similitude entre le texte d'entrée et la liste des documents à rechercher par la méthode suivante pour obtenir le texte avec la similitude la plus élevée.

Le code qui réalise ce qui précède est ci-dessous.

import re
import neologdn
import MeCab, jaconv
import pandas as pd
from gensim.models import word2vec

#chargement du modèle word2vec
MODEL_PATH = "wiki_neologd.model"
model = word2vec.Word2Vec.load(MODEL_PATH)
#Objet pour analyse morphologique
m = MeCab.Tagger()
#Objet pour le traitement normal des expressions
re_kana = re.compile('[a-zA-Z\u3041-\u309F]')
re_num = re.compile('[0-9]+')

#Documenter la fonction de normalisation avant l'analyse morphologique
def format_text(text):
  text = neologdn.normalize(text)
  return text

#Fonction pour extraire le prototype du mot indépendant de la phrase, à l'exclusion d'un caractère alphanumérique
def extract_words(text):
  words = []
  for token in m.parse(text).splitlines()[:-1]:
    if '\t' not in token: continue

    surface = token.split('\t')[0]
    pos = token.split('\t')[1].split(',')

    ok = (pos[0]=='nom' and pos[1] in ['Général','固有nom','Changer de connexion','Racine du verbe adjectif'])
    ok = (ok or (pos[0]=='adjectif' and pos[1] == 'Indépendance'))
    ok = (ok or (pos[0]=='adverbe' and pos[1] == 'Général'))
    ok = (ok or (pos[0]=='verbe' and pos[1] == 'Indépendance'))

    if ok == False: continue

    stem = pos[-3]

    if stem == '*': stem = surface
    if stem == '-': continue
    if re_kana.fullmatch(stem) and len(stem)==1: continue
    if re_num.fullmatch(stem): continue
    if stem == '': continue

    words.append(stem)
  return words
#Extraire des mots indépendants d'un ensemble de documents et créer une base de données.
def get_document_db(documents):
  id_list = list(range(len(documents)))
  words_list = []
  for d in documents:
    d = format_text(d)
    words = extract_words(d)
    #Exclure les doublons
    words = set(words)
    #Exclure les mots qui ne sont pas dans word2vec
    words = [w for w in words if w in model.wv.vocab]
    words_list.append(words)
  db = pd.DataFrame({"id":id_list, "text":documents, "word":words_list})
  return db

#Renvoie la similitude entre la liste de mots A et la liste de mots B
def calc_similarity(words1, words2):
  total = 0
  for w1 in words1:
    if w1 not in model.wv.vocab: continue
    max_sim = 0
    for w2 in words2:
      if w2 not in model.wv.vocab: continue
      sim = model.wv.similarity(w1=w1, w2=w2)
      max_sim = max(max_sim, sim)
    total += max_sim
  return total

#Calcule et renvoie la similitude entre l'instruction d'entrée et chaque document dans db
def add_similarity_to_db(text, db):
  text = format_text(text)
  words1 = extract_words(text)
  #Exclure les doublons
  words1 = set(words1)
  words1 = [w for w in words1 if w in model.wv.vocab]
  similarity = []
  for words2 in db.word:
    sim = calc_similarity(words1, words2)
    similarity.append(sim)

  similarity_df = pd.DataFrame({"similarity": similarity})
  db2 = pd.concat([db,similarity_df], axis=1)
  
  db2 = db2.sort_values(["similarity"], ascending=False)
  db2 = db2.reset_index()
  return db2

#Contrôle de sortie
#Ensemble de documents à rechercher
#Faites une liste de documents, un élément à la fois. Ici, à titre d'exemple, j'utilise des phrases qui sont correctement extraites de mes articles précédents.
documents = [
  'J'ai créé une fonction pour obtenir la prononciation japonaise en kana avec MeCab et Python. Par exemple, si vous saisissez «J'ai bien dormi aujourd'hui», il renverra «Kyowayokunemashita».',
  'J'ai créé une fonction python qui divise le japonais (chaîne de caractères katakana) en unités de mora (division mora). Mora et syllabes sont des unités de division typiques de la phonologie japonaise. Mora est un délimiteur lors du comptage des soi-disant «5, 7, 5» dans le haïku, et les sons longs (-), les sons d'incitation (tsu) et le répulsif sonore (n) sont également comptés comme un battement. Par contre, dans les syllabes, les notes longues, les sons incitatifs et les sons répulsifs ne sont pas comptés individuellement, mais sont considérés comme un battement avec le kana qui peut être une seule syllabe juste avant.',
  'J'ai créé une fonction python qui divise le japonais (chaîne de caractères katakana) en unités syllabiques (division syllabique). Mora et syllabes sont des unités de division typiques de la phonologie japonaise. Mora est un délimiteur lors du comptage des soi-disant «5, 7, 5» dans le haïku, et les sons longs (-), les sons d'incitation (tsu) et le répulsif sonore (n) sont également comptés comme un battement. Par contre, dans les syllabes, les notes longues, les sons incitatifs et les sons répulsifs ne sont pas comptés individuellement, mais sont considérés comme un battement avec le kana qui peut être une seule syllabe juste avant. Si un son long, un son incitatif et une répulsion sonore sont continus comme "brûler", le nombre de mora de 3 ou plus devient une syllabe.',
  'En Python, j'ai créé une fonction qui divise (la dernière ligne du tableau ci-dessous) par phrase et non par mot (partie).',
  '"Trouvez le nombre de 25 trillions de chiffres du plancher de 100 trillions(J'ai essayé de résoudre le problème "la notation est un système décimal)" avec python. (L'histoire originale est la fameuse question "Le 25 trillionième numéro de la droite des 100 trillions d'étages est-il pair ou impair?")',
  'Le dictionnaire par défaut de MeCab est mecab-ipadic-Ceci est un mémo de ce que j'ai fait dans mon environnement (macOS) pour passer à NEologd. Comme beaucoup de gens l'ont déjà écrit, le dictionnaire par défaut peut être changé en éditant un fichier appelé mecabrc, mais dans mon environnement il y a plusieurs mecabrc et je me demandais lequel éditer, donc lequel J'écris sur la façon dont cela fonctionnait réellement, y compris comment savoir si un fichier doit être modifié.'
]

db = get_document_db(documents)
input_texts = ["Japonais séparé","Calcul du plancher","Séparer le japonais avec Mora", "Séparer le japonais par syllabes"]
for text in input_texts:
  print(text)
  result = add_similarity_to_db(text, db)
  for sim, d in list(zip(result.similarity, result.text))[:10]:
    disp = d
    if len(d)>20: disp = d[:20]+"..."
    print(sim, disp)

La sortie est ci-dessous. Le nombre de documents est petit et il est difficile de comprendre comme exemple, mais les deux premiers résultats sont comme ça. Dans les deux derniers, les scores étaient exactement les mêmes pour Mora et syllabes. Il semble que Mora et les syllabes aient coexisté dans cet ensemble de documents. Inclure le poids des mots dans chaque document dans le calcul à l'aide de tfidf, etc. peut être mieux, mais j'aimerais le vérifier à l'avenir.

Japonais séparé
2.593316972255707 Minutes japonaises (chaîne de caractères Katakana) en unités Mora...
2.593316972255707 japonais (chaîne de caractères katakana) divisé par syllabe...
1.6599590480327606 Prononciation japonaise avec MeCab et Python...
1.5144233107566833 Le dictionnaire par défaut de MeCab est mecab-...
1.4240807592868805 En Python, pas une unité de mots (parties)...
1.18932443857193 "Trouvez les 25 trillions de chiffres de l'étage de 100 trillions...
Calcul du plancher
1.4738755226135254 "Trouvez le nombre de 25 billions de chiffres de l'étage de 100 billions de dollars...
1.1860262751579285 prononciation japonaise avec MeCab et Python...
1.1831795573234558 Minutes japonaises (chaîne de caractères Katakana) en unités Mora...
1.1831795573234558 Japonais (chaîne de caractères katakana) divisé par syllabe...
1.1831795573234558 En Python, ce n'est pas une unité de mots (parties)...
0.7110081613063812 Le dictionnaire par défaut de MeCab est mecab-...
Séparer le japonais avec Mora
3.0 minute de japonais (chaîne de caractères Katakana) en unités Mora...
3.0 Le japonais (chaîne de caractères katakana) est-il divisé en unités syllabiques?...
1.754945456981659 Prononciation japonaise avec MeCab et Python...
1.6068530082702637 En Python, pas en mots (parties)...
1.226668268442154 Le dictionnaire par défaut de MeCab est mecab-...
1.1506744921207428 "Trouvez les 25 billions de chiffres de l'étage de 100 billions...
Séparer le japonais par syllabes
3.0 minute de japonais (chaîne de caractères Katakana) en unités Mora...
3.0 Le japonais (chaîne de caractères katakana) est-il divisé en unités syllabiques?...
1.862914353609085 prononciation japonaise avec MeCab et Python...
1.6907644867897034 En Python, pas en mots (parties)...
1.2761026918888092 Le dictionnaire par défaut de MeCab Mecab-...
1.2211730182170868 "Trouvez le nombre de 25 billions de chiffres de l'étage de 100 billions de dollars...

Recommended Posts

Algorithme de recherche utilisant word2vec [python]
Rechercher sur Twitter avec Python
Algorithme en Python (dichotomie)
Algorithme Python
Python2 + mot2vec
Algorithme en Python (recherche de priorité de largeur, bfs)
Recherche de priorité de profondeur à l'aide de la pile en Python
Mémorandum Python (algorithme)
Algorithme en Python (ABC 146 C Dichotomy
Rechercher le labyrinthe avec l'algorithme python A *
Commencez à utiliser Python
Algorithme de recherche de chaînes
Scraping à l'aide de Python
Qu'est-ce qu'un algorithme? Introduction à l'algorithme de recherche] ~ Python ~
Pandas Python: recherchez DataFrame à l'aide d'expressions régulières
Recherche affinée des valeurs de race Pokemon à l'aide de Python
Algorithme A * (édition Python)
Recherche séquentielle avec Python
Manipuler Redmine à l'aide de Python Redmine
Séquence de Fibonacci utilisant Python
Exercice Python Recherche prioritaire sur 1 largeur
[Python] Recherche (itertools) ABC167C
Dichotomie avec Python
Algorithme génétique en python
[Python] Recherche (NumPy) ABC165C
Recherche de bisection (python2.7) mémo
[Python] Recherche de bisection ABC155D
Utilisation des packages Python #external
recherche complète de bits python
Algorithme en Python (méthode Bellman-Ford, Bellman-Ford)
Câblage Communication Pi-SPI avec Python
Recherche linéaire en Python
Dichotomie avec python
Calcul de l'âge à l'aide de python
Réapprendre Python (algorithme I)
Dichotomie avec Python 3
Identification de nom à l'aide de python
Notes sur l'utilisation de sous-processus Python
Recherche binaire en Python
Essayez d'utiliser Tweepy [Python2.7]
Algorithme en Python (Dijkstra)
Utiliser l'API de recherche de la Bibliothèque du Parlement national en Python
Aplatir à l'aide du rendement Python de
Scraping à l'aide de Python 3.5 async / await
[Python] BFS (recherche de priorité de largeur) ABC168D
Enregistrer des images à l'aide de requêtes python3
[S3] CRUD avec S3 utilisant Python [Python]
[Python] Essayez d'utiliser le canevas de Tkinter
Algorithme en Python (jugement premier)
Recherche de chemin dans le graphique à l'aide de Networkx
Utilisation de Quaternion avec Python ~ numpy-quaternion ~
Essayez d'utiliser Kubernetes Client -Python-
[Python] Utilisation d'OpenCV avec Python (basique)
Analyse des émotions par Python (word2vec)
Essayez une recherche similaire de recherche d'images à l'aide du SDK Python [Recherche]