Exploration de texte par word2vec etc. par python ([High School Information Department Information II] matériel pédagogique pour la formation des enseignants)

introduction

Dans le dernier article, j'ai fait un simple text mining basé sur le travail d'Aozora Bunko. https://qiita.com/ereyester/items/7c220a49c15073809c33 Cette fois, j'aimerais utiliser Word2vec pour explorer la similitude des mots. Il existe de nombreux autres articles sur Word2vec, je ne les expliquerai donc pas en détail. [Comprendre Word2Vec](https://qiita.com/g-k/items/69afa87c73654af49d36 «Comprendre Word2Vec») [Python] Comment utiliser Word2Vec Cette fois, je voudrais me concentrer sur la fonction de word2vec.Word2Vec () dans gensim.models de gensim. Le mécanisme de Word2vec compris par les images

Matériel pédagogique

[Matériel de formation des enseignants du Département de l'information du lycée "Information II" (volume principal): Ministère de l'éducation, de la culture, des sports, de la science et de la technologie](https://www.mext.go.jp/a_menu/shotou/zyouhou/detail/mext_00742.html "Département de l'information du lycée Matériel pédagogique "Information II" pour la formation des enseignants (partie principale): Ministère de l'éducation, de la culture, des sports, des sciences et de la technologie ") Chapter 3 Information and Data Science Second Half (PDF: 7.6MB)

environnement

Parties à reprendre dans le matériel pédagogique

Apprentissage 18 Text mining et reconnaissance d'images: "2. Text mining using MeCab"

Exemple d'implémentation et résultat en python

Préparation

En python, chargez un package appelé gensim pour l'apprentissage automatique avec Word2vec.

!pip install gensim

Ensuite, téléchargez le dictionnaire des émotions pour une analyse des émotions à effectuer plus tard. L'analyse des émotions est possible en trouvant la distance par rapport aux principaux termes des termes qui indiquent l'émotion avec Word2vec lors de l'analyse des émotions, mais ici, en tant que dictionnaire japonais, l'analyse des émotions est effectuée à l'aide de la table PN de l'Institut de technologie de Tokyo. Je vais.

import urllib.request
import pandas as pd

#Lien de table PN
url = 'http://www.lr.pi.titech.ac.jp/~takamura/pubs/pn_ja.dic'

#Nom de sauvegarde du fichier
file_path = 'pn_ja.dic'

with urllib.request.urlopen(url) as dl_file:
    with open(file_path, 'wb') as out_file:
        out_file.write(dl_file.read())

#Lisez le dictionnaire
dic = pd.read_csv('/content/pn_ja.dic', sep = ':', encoding= 'shift_jis', names = ('word','reading','Info1', 'PN'))

print(dic)

Le résultat de l'exécution est le suivant.

       word reading Info1        PN
0 Excellent excellent verbe 1.000000
1 bon bon adjectif 0.999995
2 Réjouis-toi Verbe joyeux 0.999979
3 louange praise verbe 0.999979
4 Medetai Medetai Adjectif 0.999645
...     ...     ...   ...       ...
55120 Non Non Verbe auxiliaire-0.999997
55121 Terribles adjectifs terribles-0.999997
55122 Nomenclature des maladies-0.999998
55123 Die no verbe-0.999999
55124 Mauvais mauvais adjectifs-1.000000

[55125 rows x 4 columns]

Ensuite, installez Mecab.

(Ajouté à 19:00 le 18/09/2020) L'auteur de mecab-python3 a souligné qu'il n'est pas nécessaire d'installer mecab, libmecab-dev et ipadic avec aptitude avant d'installer mecab-python3, je vais donc le réparer.

!pip install mecab-python3
!pip install unidic-lite

Construction de modèles et analyse de texte avec Word2vec

Convertissez le texte à analyser en texte séparé et enregistrez-le pour l'apprentissage avec word2vec. Suivez les étapes ci-dessous. (1) Téléchargez et lisez les données textuelles de "Bo-chan" pour effectuer une analyse de texte sur "Bo-chan" de Natsume Soseki. (2) Supprimez le rubis, les annotations, etc. ③ Extrayez la nomenclature, les adjectifs et les verbes du texte de "Bochan", supprimez les nombres et les mots non indépendants, convertissez-les en "écriture séparée" et convertissez-les en un fichier appelé tf.txt.

from collections import Counter
import MeCab    #Lisez MeCab
import zipfile
import os.path,glob
import re

#Spécifiez l'URL de "Bochan"
url = 'https://www.aozora.gr.jp/cards/000148/files/752_ruby_2438.zip'

#nom de sauvegarde du fichier zip
file_path = 'temp.zip'

#Ouvrez le fichier du garçon et supprimez le fichier lu
with urllib.request.urlopen(url) as dl_file:
    with open(file_path, 'wb') as out_file:
        out_file.write(dl_file.read())
        with zipfile.ZipFile(file_path) as zf:
            listfiles = zf.namelist()
            zf.extractall()

os.remove(file_path)

# shift_Lire avec jis
with open(listfiles[0], 'rb') as f:
    text = f.read().decode('shift_jis')

#Suppression de rubis, annotations, etc.
text = re.split(r'\-{5,}', text)[2]
text = re.split(r'Livre du bas:', text)[0]
text = re.sub(r'《.+?》', '', text)
text = re.sub(r'[#.+?]', '', text)
text = text.strip()

#Préparez-vous à utiliser MeCab
tagger = MeCab.Tagger()

#Erreur si non initialisé
tagger.parse("")

#Analyse morphologique avec NMeCab
node = tagger.parseToNode(text)
word_list_raw = []
result_dict_raw = {}
#Extraire la nomenclature, les adjectifs et les verbes
wordclass_list = ['nom','adjectif','verbe']
#Exclut les nombres, la non-indépendance, les synonymes et les suffixes
not_fine_word_class_list = ["nombre", "Non indépendant", "Synonyme","suffixe"]

while node:
    #Se procurer plus d'information
    word_feature = node.feature.split(",")
    #Obtenir des mots (en principe, forme de base)
    word = node.surface
    #Obtenir des paroles de partie
    word_class = word_feature[0]
    fine_word_class = word_feature[1]
    #Spécifiez ce qu'il faut extraire de la pièce et ce qu'il faut exclure
    if ((word not in ['', ' ','\r', '\u3000']) \
        and (word_class in wordclass_list) \
        and (fine_word_class not in not_fine_word_class_list)):
        #liste de mots
        word_list_raw.append(word)
        result_dict_raw[word] = [word_class, fine_word_class]
    #Passer au mot suivant
    node = node.next
print(word_list_raw)

wakachi_text = ' '.join(word_list_raw);

#nom de sauvegarde du fichier wakachi
file2_path = 'tf.txt'

with open(file2_path, 'w') as out_file:
    out_file.write(wakachi_text)

print(wakachi_text)

Le résultat de l'exécution est le suivant.

['un', 'Remise', 'Pistolet sans arme', 'Petite offre', 'Temps', 'perte', 'Shi', 'Est', 'école',…
Arme à main d'un parent, petit service, temps d'école perdu, école de temps et de minute, saut en bas ...

Vient ensuite la construction du modèle par word2vec, qui est la partie principale de cet article.

from gensim.models import word2vec
import logging

logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
sentence_data = word2vec.LineSentence('tf.txt')
model_bochan = word2vec.Word2Vec(sentence_data,
                         sg=1,        # Skip-gram
                         size=100,    #Nombre de dimensions
                         min_count=5, # min_Ignorer les mots moins de fois
                         window=12,   #Nombre maximum de mots en contexte
                         hs=0,        #Hiérarchie Softmax(0 pour un échantillonnage négatif)
                         negative=5,  #Échantillonnage négatif
                         iter=10      #Nombre d'époque
                         )

model_bochan.save('test.model')

Importez le word2vec du module gensim et construisez le modèle avec Word2Vec.

Deux modèles d'apprentissage sont disponibles dans word2vec.

Je vais omettre ces deux explications, mais comme le skip-gramme est utilisé dans le matériel didactique, le skip-gram est utilisé en conséquence. (En général, skip-gram montre de meilleures performances en CBOW et skip-gram)

Le nombre de dimensions du mot vecteur est le même que la valeur par défaut, mais il est défini sur 100. La condition pour rejeter des mots est d'ignorer les mots qui apparaissent moins de 5 fois. Le nombre maximum de mots avant et après la reconnaissance en tant que contexte est de 12.

Il existe deux algorithmes qui accélèrent l'apprentissage. -Hierarchical Softmax -Negative Sampling J'omettrai ces deux explications. J'utilise l'échantillonnage négatif ici.

Cette explication est http://tkengo.github.io/blog/2016/05/09/understand-how-to-learn-word2vec/ Est détaillé.

Le nombre d'itérations de corpus est spécifié comme 10. Il s'agit du nombre d'époques indiquant combien de fois une donnée d'apprentissage est entraînée par le réseau neuronal.

Cela nous a permis de construire le modèle.

Ensuite, regardons la similitude des mots ainsi que le matériel pédagogique. Recherchez le mot rouge.

model   = word2vec.Word2Vec.load('/content/test.model')
results = model.most_similar(positive=['rouge'], topn=100)

for result in results:
    print(result[0], '\t', result[1])

Le résultat de l'exécution est le suivant.

:
2020-09-16 12:30:12,986 : INFO : precomputing L2-norms of word weight vectors
Chemise 0.9854607582092285
Ennuyeux 0.9401918053627014
Prénom 0.9231084585189819
Gorki 0.9050831198692322
Savoir 0.8979452252388
Doux 0.897865891456604
D'accord 0.8932155966758728
Russie Aya 0.8931306004524231
Madone 0.890703558921814
:

Comme mentionné ci-dessus, il s'est avéré que les personnages tels que les chemises rouges venaient au sommet. Ensuite, comme exemple de soustraction des éléments du modèle, soustrayons "chemise" de "madonna".

model = word2vec.Word2Vec.load('/content/test.model')

results = model.most_similar(positive=['Madone'], negative=['chemise'], topn=100)
for result in results:
    print(result[0], '\t', result[1])

Le résultat de l'exécution est le suivant.

:
INFO : precomputing L2-norms of word weight vectors
Voix 0.2074282020330429
Geisha 0.1831434667110443
Boulette 0.13945674896240234
Divertissement 0.13744047284126282
Tenfura 0.11241232603788376
Pâte 0.10779635608196259
Enseignant 0.08393052220344543
Esprit 0.08120302855968475
Gentillesse 0.0712042897939682
:

En soustrayant l'élément de chemise de Madonna, nous avons pu extraire des éléments tels que la voix, le professeur, la geisha et la gentillesse.

Ce qui suit est détaillé sur l'addition et la soustraction d'éléments par word2vec. https://www.pc-koubou.jp/magazine/9905

Analyse simple des émotions par table PN

L'analyse des émotions est possible même avec Word2Vec en trouvant la distance des principaux termes de l'émotion, mais ici je voudrais analyser avec le dictionnaire des émotions (PN Table) lu ci-dessus comme dans le matériel pédagogique.

Commencez par convertir le dictionnaire du type dataframe au type dict pour le rendre facile à manipuler.

dic2 = dic[['word', 'PN']].rename(columns={'word': 'TERM'})

#Convertir la table PN du bloc de données en type dict
word_list = list(dic2['TERM'])
pn_list = list(dic2['PN'])  #Le type de contenu est numpy.float64

pn_dict = dict(zip(word_list, pn_list))

print(pn_dict)

Le résultat de l'exécution est le suivant.

{'Excellent': 1.0, 'bien': 0.9999950000000001, 'Réjouir': 0.9999790000000001, 'louange': 0.9999790000000001, 'Toutes nos félicitations': 0.9996450000000001,…

Les termes positifs sont définis sur une valeur proche de 1 et les termes négatifs sur une valeur proche de -1.

Ensuite, prenez la nomenclature et les adjectifs de "Bochan" et supprimez les nombres et les suffixes. Essayez d'afficher des mots positifs et négatifs en combinant un tableau de fréquence des mots et un dictionnaire des émotions.

#Préparez-vous à utiliser MeCab
tagger = MeCab.Tagger()

#Erreur si non initialisé
tagger.parse("")

#Analyse morphologique avec NMeCab
node = tagger.parseToNode(text)
word_list_raw = []
extra_result_list = []
#Extraire la nomenclature, les adjectifs et les verbes
wordclass_list = ['nom','adjectif']
#Exclut les nombres, la non-indépendance, les synonymes et les suffixes
not_fine_word_class_list = ["nombre","suffixe", "Non indépendant"]

while node:
    #Se procurer plus d'information
    word_feature = node.feature.split(",")
    #Obtenir des mots (en principe, forme de base)
    word = node.surface
    #Obtenir des paroles de partie
    word_class = word_feature[0]
    fine_word_class = word_feature[1]
    #Spécifiez ce qu'il faut extraire de la pièce et ce qu'il faut exclure
    if ((word not in ['', ' ','\r', '\u3000']) \
        and (word_class in wordclass_list) \
        and (fine_word_class not in not_fine_word_class_list)):
        #liste de mots
        word_list_raw.append(word)
    #Passer au mot suivant
    node = node.next

freq_counterlist_raw = Counter(word_list_raw)
dict_freq_raw = dict(freq_counterlist_raw)

extra_result_list = []
for k, v in dict_freq_raw.items():
    if k in pn_dict:
        extra_result_list.append([k, v, pn_dict[k]])

extra_result_pn_sorted_list = sorted(extra_result_list, key=lambda x:x[2], reverse=True)
print("Mots positifs")
display(extra_result_pn_sorted_list[:10])
print("Mots négatifs")
display(extra_result_pn_sorted_list[-10:-1])

Le résultat de l'exécution est le suivant.

Mots positifs
[['Toutes nos félicitations', 1, 0.9996450000000001],
 ['bien', 2, 0.9993139999999999],
 ['heureux', 1, 0.998871],
 ['Assortiment', 1, 0.998208],
 ['Crédit', 2, 0.997308],
 ['Justice', 1, 0.9972780000000001],
 ['Impressionné', 10, 0.997201],
 ['Excusez-moi', 1, 0.9967889999999999],
 ['Encouragement', 1, 0.9959040000000001],
 ['pertinence', 1, 0.995553]]
Mots négatifs
[['Rugueux', 13, -0.9993340000000001],
 ['étroit', 7, -0.999342],
 ['Du froid', 1, -0.999383],
 ['Châtiment', 5, -0.9994299999999999],
 ['ennemi', 3, -0.9995790000000001],
 ['douloureux', 1, -0.9997879999999999],
 ['pauvre', 6, -0.9998309999999999],
 ['Absent', 338, -0.9999969999999999],
 ['malade', 6, -0.9999979999999999]]

Le deuxième élément de la liste est la fréquence d'apparition (nombre de fois) et le troisième est une valeur qui indique si elle est positive ou négative. Enfin, regardons lequel des mots positifs et négatifs est souvent utilisé pour "Bo-chan" dans son ensemble. (Cependant, la fréquence d'apparition des mots n'est pas utilisée selon le matériel pédagogique)

pos_n = sum(x[2] > 0 for x in extra_result_pn_sorted_list)

print(pos_n)

neg_n = sum(x[2] < 0 for x in extra_result_pn_sorted_list)

print(neg_n)

Le résultat de l'exécution est le suivant.

182
1914

J'ai trouvé que les mots négatifs sont souvent utilisés dans "Bo-chan".

commentaire

En ce qui concerne le traitement lié à word2vec, des résultats similaires n'ont pas été obtenus avec python et R, donc je vais essayer de trouver la cause si je peux me le permettre à l'avenir.

Code source

https://gist.github.com/ereyester/101ae0da17e747b701b67fe9fe137b84

Recommended Posts

Exploration de texte par word2vec etc. par python ([High School Information Department Information II] matériel pédagogique pour la formation des enseignants)
[Information I / Information II du Département d'Information du Lycée] Résumé du matériel pédagogique pour la formation des enseignants par python
Classification binar par arbre de décision par python ([High school information department information II] pédagogique pour la formation des enseignants)
Classification par méthode k-voisinage (kNN) par python ([High school information department information II] matériel pédagogique pour la formation des enseignants)
Analyse des données par regroupement à l'aide de la méthode k-means (python) ([High school information department information II] pédagogique pour la formation des enseignants)
[Information du département d'information du lycée I] Matériel pédagogique pour la formation des enseignants: Format des données et visualisation (python)
Analyse des composants principaux avec python (version Scikit-learn, version pandas et numpy) ([High school information department information II] didacticiel pour la formation des enseignants)
Détection d'objets à l'aide de YOLO (python) (matériel didactique [Information du département d'information du lycée II] pour la formation des enseignants)
[Informations sur les lignes directrices d'apprentissage du lycée I] Matériel pédagogique pour la formation des enseignants: mise en œuvre de la méthode Huffman par python
Matériel pédagogique Web pour apprendre Python