Ist es für Anfänger (insbesondere Selbststudenten) nicht am schwierigsten, Korpus (eine große Anzahl von Sätzen) zu sammeln, wenn sie eine Verarbeitung natürlicher Sprache mit maschinellen Lernalgorithmen auf Japanisch durchführen?
In dem Thema "Deep Learning from Grundle ❷ ~ Natural Language Processing ~" und anderen Büchern steht im Grunde der Umgang mit dem englischen Korpus im Mittelpunkt, und der japanische Korpus hat eine andere Angewohnheit als Englisch. Die aktuelle Situation ist, dass es schwierig ist, die Verarbeitung von zu erleben. (Zumindest hatte ich große Probleme, weil ich überhaupt keine japanischen Korpora sammeln konnte.)
Also habe ich dieses Mal den Artikel "Livedoor News" (deutsche Mitteilung) verwendet und ihn wahrscheinlich einmal für diejenigen bekommen, die maschinelles Lernen betreiben. Ich möchte ein gutes Buch "Deep Learning von Grund auf ❷ ~ Verarbeitung natürlicher Sprache ~" auf Japanisch implementieren.
Dieses Mal werde ich den Korpus durch Japanisch ersetzen und ihn für die folgende Reihe von "Deep Learning" von Grund auf neu implementieren. Im Fall von Japanisch ist die Vorverarbeitung im Gegensatz zu Englisch problematisch. Konzentrieren Sie sich daher bitte auf diesen Bereich.
Ziel
Betreff: "Deep Learning von Grund auf neu ❷"
Umfang dieser Zeit: Kapitel 2 Verteilte Darstellung von natürlicher Sprache und Wörtern 2.3 Zählbasierte Methode ~ 2.4.5 Auswertung mit PTB-Datensatz
Mac OS(Mojave) Python3(Python 3.7.4) jupiter Notebook
Bei den Originaldaten handelt es sich um eine Textdatei, die für jeden Artikelliefertermin erstellt wird. Dies ist zwar umständlich (wahrscheinlich mehr als 100 Dateien). Kombinieren Sie daher zunächst alle Textdateien zu einer neuen Textdatei .. Sie können mehrere Textdateien mit dem folgenden Befehl (für Mac) kombinieren.
Terminal
$ cat ~/Verzeichnisname/*.txt >Neuer Name der Textdatei.txt
Referenz
https://ultrabem-branch3.com/informatics/commands_mac/cat_mac
[Beiseite]
Es ist wirklich nur eine Seite, aber ich persönlich hatte mit dem oben genannten Prozess zu kämpfen. ..
Zuerst bin ich in die Datei gegangen und habe den Befehl "
cat * .txt> new text file name.txt`` "ausgeführt, aber der Vorgang wurde wahrscheinlich vollständig abgeschlossen, wahrscheinlich weil der Verzeichnisname nicht angegeben wurde. (Vielleicht hat der Platzhalter versucht, alle Textdateien auf meinem PC zu lesen?) Und am Ende erhielt ich eine Bang-Bang-Warnung mit der Aufschrift "Nicht genug Speicherplatz!" .. .. Bitte seien Sie vorsichtig.
** ⑴ Trennung von Sätzen **
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: #Anmerkung 1)
original_corpus = f.read()
text = re.sub("http://news.livedoor.com/article/detail/[0-9]{7}/","", original_corpus) #Anmerkung 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) #Notiz 3)
text = re.sub("[\f\n\r\t\v]","", text)
text = re.sub(" ","", text)
text = re.sub("[「」]","", text)
text = [re.sub("[()]","", text)]
#<Punkt>
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)
Anmerkung 1) Dieses Mal bereiten wir im Gegensatz zu "Deep Learning ❷ von Grund auf neu" den Korpus selbst vor, damit wir den Zielkorpus lesen können. Auch dieses Mal wird "dokujo-tsushin-half.txt" gelesen, aber obwohl ich ursprünglich versucht habe, "dokujo-tsushin-all.txt" zu lesen, wurde eine Warnung ausgegeben, dass es aufgrund von Überkapazität nicht gelesen werden konnte. Daher habe ich "alle" aufgegeben und "die Hälfte" verwendet (⓪ die Kombination von vorbereiteten Textdateien führte nur die Hälfte aller Dateien aus).
**
with open('words_list.pickle', mode='rb') as f:
words_list = pickle.load(f)
print(words_list) #Wenn Sie das Ladeergebnis nicht anzeigen müssen, ist diese Beschreibung nicht erforderlich
# =>Ausgabe
#[['Freund', 'Vertreter', 'von', 'Rede', '、', 'Deutschland', 'Frau', 'Ist', 'Wie', 'Machen', 'Hand', 'Ist', '?', 'demnächst', 'Juni', '・', 'Braut', 'Wann', 'Anruf', 'Sein', 'Juni', '。', 'Deutschland', 'Frau', 'von', 'Während ~', 'Zu', 'Ist', 'mich selber', 'von', 'Formel', 'Ist', 'noch', 'Nana', 'vonZu', 'Anruf', 'Re', 'Hand', 'Gerade', '…', '…', 'WannichU.', 'Feier', 'Armut', 'Status', 'von', 'Mann', 'Ebenfalls', 'Viele', 'von', 'damit', 'Ist', 'Nanaich', 'Ich wundere mich', 'U.', 'Oder', '?', 'SaらZu', 'Teilnahme', 'Anzahl', 'Zu', 'Stapel', 'Hand', 'Gehen', 'Wann', '、', 'こHmmNana', 'Bitte', 'ごWann', 'Zu', 'Sa', 'Sein', 'こWann', 'Ebenfalls', '少Nanaく', 'Nanaich', '。', 'Bitte', 'Aber', 'Gibt es', 'Hmm', 'Ist', 'aber', '…', '…', 'Freund', 'Vertreter', 'von', 'Rede', '、', 'Schließlich', 'Hand', 'くRe', 'Nanaich', 'Oder', 'Nana', '?', 'SaHand', 'そHmmNana', 'Wannき', '、', 'Deutschland', 'Frau', 'Ist', 'Wie', 'Korrespondenz', 'Shi', 'Tara', 'Gut', 'Oder', '?', 'Vor kurzem', 'Ist', 'Wann', 'das Internet', 'etc', 'damit', 'Suche', 'すRe', 'Wenn', 'Freund', 'Vertreter', 'Rede', 'zum', 'von', 'Beispielsatz', 'Seite? ˅', 'Aber', 'TaくSaHmm', 'aus', 'Hand', 'Kommen Sie', 'vondamit', '、', 'そReら', 'Zu', 'Referenz', 'Zu', 'すRe', 'Wenn', '、', 'Sicher', 'Nana', 'Ebenfallsvon', 'Ist', 'Wer', 'damitEbenfalls', 'Erstellen', 'damitきる', '。', 'ShiOderShi', 'Yuri', 'SaHmm', '33', 'Alter', 'Ist', 'Netz', 'Zu', 'Referenz', 'Zu', 'Shi', 'Hand', 'Erstellen', 'Shi', 'Ta', 'Ebenfallsvonvon', 'こRe', 'damit', '本当Zu', 'Gut', 'von', 'Oder', 'Angst', 'damitShi', 'Ta', '。', '一Mann暮らShi', 'Nana', 'vondamit', '聞Oder', 'einstellen', 'Hand', 'Impressionen', 'Zu', 'Ichi', 'Hand', 'くSein', 'Mann', 'Ebenfalls', 'ich', 'Nanaich', 'Shi', '、', 'Oder', 'Wann', 'Ichi', 'Hand', 'andere', 'von', 'Freund', 'Zu', 'Nimm dir die Mühe', '聞Oder', 'einstellenる', 'von', 'Ebenfalls', 'Wie', 'Oder', 'Wann',・ ・ ・ Unten weggelassen
** ⑵ Erstellen Sie eine Liste mit IDs für Wörter **
def preprocess(text):
word_to_id = {}
id_to_word = {}
#<Punkt>
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['Frau']:", word_to_id['Frau'])
print("word_to_id['Ehe']:", word_to_id['Ehe'])
print("word_to_id['Mann']:", word_to_id['Mann'])
# =>Ausgabe
# 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]:Freund
# id_to_word[1]:Vertreter
# id_to_word[2]:von
# word_to_id['Frau']: 6
# word_to_id['Ehe']: 456
# word_to_id['Mann']: 1453
Punkt
-Die Vorverarbeitungsfunktion ist im Grunde die gleiche wie in diesem Buch, aber dieses Mal wurde die Wortteilung des Satzes bereits vorgenommen, sodass dieser Teil gelöscht wurde, und im Gegensatz zu diesem Buch wird der for-Satz zweimal gedreht. Der Punkt ist, eine ID zu geben.
Der Grund, warum der for-Satz zweimal gedreht wird, ist, dass das Wort in der Doppelliste enthalten ist, da das Wort durch die Teilung geteilt wird, die sich von diesem Buch unterscheidet.
Ich werde die Details des Folgenden weglassen, da es viele Teile gibt, die sich mit dem Inhalt des Buches überschneiden, aber ich würde es begrüßen, wenn Sie darauf verweisen könnten, da es an einigen Stellen Kommentare enthält.
#Erstellen einer Matrix für das gleichzeitige Auftreten
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
#Beurteilung der Ähnlichkeit zwischen Vektoren (cos Ähnlichkeit)
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)
#Rangfolge der Ähnlichkeit zwischen Vektoren
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
#Verbesserung der Wortrelevanzindikatoren durch positive gegenseitige Information (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:
#Dimensionsreduktion durch SVD mit 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 = ['Weiblich', 'Ehe', 'er', 'Mote']
for query in querys:
most_similar(query, word_to_id, id_to_word, word_vecs, top=5)
# =>Unten das Ausgabeergebnis
"""
[query]Weiblich
männlich: 0.6902421712875366
Etc.: 0.6339510679244995
Modell-: 0.5287646055221558
Generation: 0.5057054758071899
Schicht: 0.47833186388015747
[query]Ehe
Liebe: 0.5706729888916016
Dating: 0.5485040545463562
Gegner: 0.5481910705566406
?。: 0.5300850868225098
Zehn: 0.4711574614048004
[query]er
Freundin: 0.7679144740104675
Freund: 0.67448890209198
Mann: 0.6713247895240784
Elternteil: 0.6373711824417114
Ehemalige: 0.6159241199493408
[query]Mote
Ru: 0.6267833709716797
Erwägung: 0.5327887535095215
Twink: 0.5280393362045288
Mädchen: 0.5190156698226929
Fahrrad: 0.5139431953430176
"""
Recommended Posts