N'est-il pas le plus difficile pour les débutants (en particulier ceux qui étudient eux-mêmes) de collecter un corpus (une grande quantité de phrases) lorsqu'ils effectuent un traitement du langage naturel à l'aide d'algorithmes d'apprentissage automatique en japonais?
Dans le sujet "Deep Learning from scratch ❷ ~ Natural language processing ~" et d'autres livres, la gestion du corpus anglais est fondamentalement au centre de l'attention, et le corpus japonais a une habitude différente de l'anglais. La situation actuelle est qu'il est difficile de faire l'expérience du traitement des fichiers. (Au moins, j'ai eu beaucoup de problèmes parce que je ne pouvais pas du tout collecter de corpus japonais.)
Donc, cette fois, j'ai utilisé l'article de "liveoor news" (communication allemande), et probablement si vous êtes un apprenant machine, vous l'avez obtenu une fois. Je voudrais mettre en œuvre un bon livre "Deep Learning from scratch ❷ ~ Natural language processing ~" en japonais.
Cette fois, je remplacerai le corpus par le japonais et l'implémenterai pour la gamme suivante de "Deep Learning ❷ made from scratch". Dans le cas du japonais, contrairement à l'anglais, le prétraitement est gênant, veuillez donc vous concentrer sur ce domaine.
Cible
Objet: "Deep Learning from scratch"
Portée de cette période: Chapitre 2 Représentation distribuée du langage naturel et des mots 2.3 Méthode basée sur le comptage ~ 2.4.5 Évaluation avec l'ensemble de données PTB
Mac OS(Mojave) Python3(Python 3.7.4) jupiter Notebook
Les données d'origine sont un fichier texte créé pour chaque date de livraison d'article, ce qui est gênant comme tel (probablement plus de 100 fichiers), alors combinez d'abord tous les fichiers texte dans un nouveau fichier texte .. Vous pouvez combiner plusieurs fichiers texte avec la commande suivante (pour mac).
Terminal
$ cat ~/Nom du répertoire/*.txt >Nouveau nom de fichier texte.txt
Référence
https://ultrabem-branch3.com/informatics/commands_mac/cat_mac
[De côté]
C'est vraiment juste un aparté, mais j'ai personnellement eu du mal avec le processus ci-dessus. ..
Au début, je me suis déplacé vers le fichier et j'ai exécuté la commande "
cat * .txt> new text file name.txt`` ", mais le processus était complètement terminé probablement parce que le nom du répertoire n'était pas spécifié. (Peut-être que le joker essayait de lire tous les fichiers texte sur mon PC?), Et à la fin, j'ai reçu un avertissement en claquant en disant «Pas assez d'espace! .. .. S'il vous plaît soyez prudente.
** ⑴ Séparation des phrases **
python
import sys
sys.path.append('..')
import re
import pickle
from janome.tokenizer import Tokenizer
import numpy as np
import collections
with open("corpus/dokujo-tsushin/dokujo-tsushin-half.txt", mode="r",encoding="utf-8") as f: #Note 1)
original_corpus = f.read()
text = re.sub("http://news.livedoor.com/article/detail/[0-9]{7}/","", original_corpus) #Note 2)
text = re.sub("[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\+[0-9]{4}","", text) #Note 3)
text = re.sub("[\f\n\r\t\v]","", text)
text = re.sub(" ","", text)
text = re.sub("[「」]","", text)
text = [re.sub("[()]","", text)]
#<Point>
t = Tokenizer()
words_list = []
for word in text:
words_list.append(t.tokenize(word, wakati=True))
with open("words_list.pickle",mode='wb') as f:
pickle.dump(words_list, f)
Note 1) Cette fois, contrairement à "Deep Learning ❷ made from scratch", nous préparons le corpus nous-mêmes, nous allons donc lire le corpus cible. De plus, cette fois, il lit "dokujo-tsushin-half.txt", mais bien que j'essayais à l'origine de lire "dokujo-tsushin-all.txt", un avertissement a été émis indiquant qu'il ne pouvait pas être lu en raison d'une surcapacité. Par conséquent, j'ai abandonné "tout" et utilisé "la moitié" (⓪ la combinaison de fichiers texte pré-préparés n'a exécuté que la moitié de tous les fichiers).
**
with open('words_list.pickle', mode='rb') as f:
words_list = pickle.load(f)
print(words_list) #Si vous n'avez pas besoin d'afficher le résultat du chargement, cette description est inutile
# =>production
#[['ami', 'représentant', 'de', 'discours', '、', 'Allemagne', 'femme', 'Est', 'Comment', 'Faire', 'main', 'Est', '?', 'bientôt', 'juin', '・', 'la mariée', 'Quand', 'Appel', 'Être', 'juin', '。', 'Allemagne', 'femme', 'de', 'Pendant ~', 'À', 'Est', 'moi même', 'de', 'formule', 'Est', 'encore', 'Nana', 'deÀ', 'Appel', 'Ré', 'main', 'Juste', '…', '…', 'QuandjeU', 'fête', 'La pauvreté', 'Statut', 'de', 'Homme', 'Aussi', 'Beaucoup', 'de', 'alors', 'Est', 'Nanaje', 'je me demande', 'U', 'Ou', '?', 'SaらÀ', 'Présence', 'Nombre de fois', 'À', 'Empiler', 'main', 'Aller', 'Quand', '、', 'こHmmNana', 'S'il vous plaît', 'ごQuand', 'À', 'Sa', 'Être', 'こQuand', 'Aussi', '少Nanaく', 'Nanaje', '。', 'S'il vous plaît', 'Mais', 'y a-t-il', 'Hmm', 'Est', 'mais', '…', '…', 'ami', 'représentant', 'de', 'discours', '、', 'finalement', 'main', 'くRé', 'Nanaje', 'Ou', 'Nana', '?', 'Samain', 'そHmmNana', 'Quandき', '、', 'Allemagne', 'femme', 'Est', 'Comment', 'Correspondance', 'Shi', 'Tara', 'Bien', 'Ou', '?', 'Récemment', 'Est', 'Quand', 'l'Internet', 'etc', 'alors', 'Chercher', 'すRé', 'Si', 'ami', 'représentant', 'discours', 'pour', 'de', 'Exemple de phrase', 'site', 'Mais', 'TaくSaHmm', 'En dehors', 'main', 'viens', 'dealors', '、', 'そRéら', 'À', 'référence', 'À', 'すRé', 'Si', '、', 'Sûr', 'Nana', 'Ausside', 'Est', 'Qui', 'alorsAussi', 'Créer', 'alorsきる', '。', 'ShiOuShi', 'Yuri', 'SaHmm', '33', 'âge', 'Est', 'Net', 'À', 'référence', 'À', 'Shi', 'main', 'Créer', 'Shi', 'Ta', 'Aussidede', 'こRé', 'alors', '本当À', 'Bien', 'de', 'Ou', 'anxiété', 'alorsShi', 'Ta', '。', '一Homme暮らShi', 'Nana', 'dealors', '聞Ou', 'Ensemble', 'main', 'Impressions', 'À', 'Ichi', 'main', 'くÊtre', 'Homme', 'Aussi', 'je', 'Nanaje', 'Shi', '、', 'Ou', 'Quand', 'Ichi', 'main', 'autre', 'de', 'ami', 'À', 'Prends la peine', '聞Ou', 'Ensembleる', 'de', 'Aussi', 'Comment', 'Ou', 'Quand',・ ・ ・ Omis ci-dessous
** ⑵ Créez une liste avec des identifiants pour les mots **
def preprocess(text):
word_to_id = {}
id_to_word = {}
#<Point>
for words in words_list:
for word in words:
if word not in word_to_id:
new_id = len(word_to_id)
word_to_id[word] = new_id
id_to_word[new_id] = word
corpus = [word_to_id[w] for w in words for words in words_list]
return corpus, word_to_id, id_to_word
corpus, word_to_id, id_to_word = preprocess(text)
print('corpus size:', len(corpus))
print('corpus[:30]:', corpus[:30])
print()
print('id_to_word[0]:', id_to_word[0])
print('id_to_word[1]:', id_to_word[1])
print('id_to_word[2]:', id_to_word[2])
print()
print("word_to_id['femme']:", word_to_id['femme'])
print("word_to_id['mariage']:", word_to_id['mariage'])
print("word_to_id['mari']:", word_to_id['mari'])
# =>production
# corpus size: 328831
# corpus[:30]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 5, 6, 2, 22, 23, 7, 24, 2]
# id_to_word[0]:ami
# id_to_word[1]:représentant
# id_to_word[2]:de
# word_to_id['femme']: 6
# word_to_id['mariage']: 456
# word_to_id['mari']: 1453
Point
-La fonction de prétraitement est fondamentalement la même que celle de ce livre, mais cette fois, la division des mots de la phrase a déjà été effectuée, de sorte que la partie a été supprimée, et contrairement à ce livre, la phrase for est tournée deux fois. Le but est de donner un identifiant.
La raison pour laquelle la phrase for est tournée deux fois est que le mot est inclus dans la liste double parce que le mot est divisé par la division, qui est différente de ce livre.
Je vais omettre les détails de ce qui suit car il y a de nombreuses parties qui chevauchent le contenu du livre, mais je vous serais reconnaissant si vous pouviez vous y référer car il contient des commentaires à certains endroits.
#Créer une matrice de cooccurrence
def create_co_matrix(corpus, vocab_size, window_size=1):
corpus_size = len(corpus)
co_matrix = np.zeros((vocab_size, vocab_size), dtype=np.int32)
for idx, word_id in enumerate(corpus):
for i in range(1, window_size + 1):
left_idx = idx - i
right_idx = idx + i
if left_idx >= 0:
left_word_id = corpus[left_idx]
co_matrix[word_id, left_word_id] += 1
if right_idx < corpus_size:
right_word_id = corpus[right_idx]
co_matrix[word_id, right_word_id] += 1
return co_matrix
#Jugement de similitude entre les vecteurs (similitude cos)
def cos_similarity(x, y, eps=1e-8):
nx = x / (np.sqrt(np.sum(x ** 2)) + eps)
ny = y / (np.sqrt(np.sum(y ** 2)) + eps)
return np.dot(nx, ny)
#Classement de la similitude entre les vecteurs
def most_similar(query, word_to_id, id_to_word, word_matrix, top=5):
if query not in word_to_id:
print('%s is not found' % query)
return
print('\n[query] ' + query)
query_id = word_to_id[query]
query_vec = word_matrix[query_id]
vocab_size = len(id_to_word)
similarity = np.zeros(vocab_size)
for i in range(vocab_size):
similarity[i] = cos_similarity(word_matrix[i], query_vec)
count = 0
for i in (-1 * similarity).argsort():
if id_to_word[i] == query:
continue
print(' %s: %s' % (id_to_word[i], similarity[i]))
count += 1
if count >= top:
return
#Améliorer les indicateurs de pertinence des mots à l'aide d'informations mutuelles positives (PPMI)
def ppmi(C, verbose=False, eps = 1e-8):
M = np.zeros_like(C, dtype=np.float32)
N = np.sum(C)
S = np.sum(C, axis=0)
total = C.shape[0] * C.shape[1]
cnt = 0
for i in range(C.shape[0]):
for j in range(C.shape[1]):
pmi = np.log2(C[i, j] * N / (S[j]*S[i]) + eps)
M[i, j] = max(0, pmi)
if verbose:
cnt += 1
if cnt % (total//100) == 0:
print('%.1f%% done' % (100*cnt/total))
return M
window_size = 2
wordvec_size = 100
corpus, word_to_id, id_to_word = preprocess(text)
vocab_size = len(word_to_id)
print('counting co-occurrence ...')
C = create_co_matrix(corpus, vocab_size, window_size)
print('calculating PPMI ...')
W = ppmi(C, verbose=True)
print('calculating SVD ...')
try:
#Réduction de dimension par SVD en utilisant sklearn
from sklearn.utils.extmath import randomized_svd
U, S, V = randomized_svd(W, n_components=wordvec_size, n_iter=5,
random_state=None)
except ImportError:
U, S, V = np.linalg.svd(W)
word_vecs = U[:, :wordvec_size]
querys = ['Femme', 'mariage', 'il', 'Mote']
for query in querys:
most_similar(query, word_to_id, id_to_word, word_vecs, top=5)
# =>Ci-dessous, le résultat de sortie
"""
[query]Femme
Masculin: 0.6902421712875366
Etc.: 0.6339510679244995
modèle: 0.5287646055221558
génération: 0.5057054758071899
couche: 0.47833186388015747
[query]mariage
amour: 0.5706729888916016
Sortir ensemble: 0.5485040545463562
Adversaire: 0.5481910705566406
?。: 0.5300850868225098
Dix: 0.4711574614048004
[query]il
Petite amie: 0.7679144740104675
copain: 0.67448890209198
mari: 0.6713247895240784
parent: 0.6373711824417114
Ancien: 0.6159241199493408
[query]Mote
Ru: 0.6267833709716797
Considération: 0.5327887535095215
Minet: 0.5280393362045288
Les filles: 0.5190156698226929
vélo: 0.5139431953430176
"""
Recommended Posts