Dieser Artikel bezieht sich auf Teil ❷ von Sammlung und Klassifizierung von Informationen zum maschinellen Lernen (Konzept).
Seit der eigentlichen Untersuchung sind mehrere Monate vergangen, daher kann sie geringfügig von der aktuellen Situation abweichen. Bitte beachten Sie auch im Voraus, dass die Ergebnisse nicht zufriedenstellend sind.
Ich bin neu in Qiita und Python, daher gibt es vielleicht viele seltsame Beschreibungen, aber ich würde es begrüßen, wenn Sie diese kommentieren könnten.
Der in diesem Artikel erläuterte Prozess ist wie folgt.
❶ Site-Crawl Platzieren Sie den gecrawlten Artikel im Verzeichnis bookmarks.crawled. ↓ ❷ Artikel in Python-Objekt verwandeln Erstellen Sie für jeden Artikel ein Python-Objekt. ↓ ❸ Corpus in Python-Objekt Konvertieren Sie den gesamten Dokumentensatz als Korpus in ein Python-Objekt. ↓ ❹ Klassifizierung nach Themenmodell Verwenden Sie diesen Korpus, um zu versuchen, nach Themenmodell zu klassifizieren.
Die Details des Thesaurus sind durcheinander, aber ansonsten werde ich ihn Schritt für Schritt so weit wie möglich erklären.
In ❷ von Sammlung und Klassifizierung von Informationen zum maschinellen Lernen (Konzept) bestand das Szenario darin, die von FESS gesammelten Ergebnisse direkt einzugeben, diesmal jedoch [ Verknüpfungsverzeichnis und Konvertierung von einfachem Text](http://qiita.com/suchowan/items/6556756d2e816c7255b7#5-%E3%83%97%E3%83%AC%E3%82%A4%E3%83%B3 % E3% 83% 86% E3% 82% AD% E3% 82% B9% E3% 83% 88% E3% 82% AF% E3% 83% AD% E3% 83% BC% E3% 83% AB% E3 % 83% 89% E3% 82% B3% E3% 83% B3% E3% 83% 86% E3% 83% B3% E3% 83% 84% E3% 83% 87% E3% 82% A3% E3% 83 % AC% E3% 82% AF% E3% 83% 88% E3% 83% AA) Der von crawl.rb heruntergeladene Inhalt wird unter dem Verzeichnis bookmarks.crawled abgelegt und eingegeben.
Wenn Sie die von FESS gesammelten Ergebnisse direkt eingeben,
・ Alte Dokumente verfallen ・ Doppelte Artikel und weniger wichtige Artikel, die bei der manuellen Artikelklassifizierung ausgeschlossen wurden, werden wiederhergestellt.
Weil.
Lesen Sie die HTML-Datei im Verzeichnis bookmarks.crawled und speichern Sie sie in einem Python Article-Klassenobjekt.
Artikelklasse
Attribut
Pfad HTML-Dateipfad
Inhalt Eine HTML-Datei mit entfernten HTML-Tags
Liste der Nomenklaturen im Token-Inhalt(list of string)
Die Ergebnisse der Bibliotheksumfrage von Text aus HTML eines Blogs mit Python 2015 extrahieren sind hilfreich.
Wenn Sie es ernsthaft implementieren möchten, sollten Sie Webstemmer verwenden. Es ist jedoch erforderlich, im Voraus eine Vorlage für jede Blog-Site zu erstellen, was kompliziert ist. Ich habe es diesmal nicht benutzt.
Die implementierte Artikelklasse basiert auf dem regulären Ausdruck von extractcontent.
(1) janome
Ich habe versucht, die japanische morphologische Analysebibliothek [janome] von Pure Python (http://mocobeta.github.io/janome/) zu verwenden. Da das Wörterbuch fast dieselbe Struktur wie MeCab hat und die alphabetischen Wörter in voller Breite definiert sind, haben wir für die Vorverarbeitung die Konvertierungsbibliothek mit halber Breite und voller Breite mojimoji verwendet. ..
article_janome.py
import codecs
import re
import mojimoji
from janome.tokenizer import Tokenizer
class Article:
encodings = [
"utf-8",
"cp932",
"euc-jp",
"iso-2022-jp",
"latin_1"
]
tokenizer = Tokenizer("user_dic.csv", udic_type="simpledic", udic_enc="utf8")
def __init__(self,path):
print(path)
self.path = path
self.contents = self.preprocess(self.get_contents(path))
self.tokens = [token.surface for token in self.tokenizer.tokenize(self.contents) if re.match("Benutzerdefinierte Nomenklatur|Substantiv,(Einzigartig|Allgemeines|Sa seltsam)", token.part_of_speech)]
def get_contents(self,path):
exceptions = []
for encoding in self.encodings:
try:
all = codecs.open(path, 'r', encoding).read()
parts = re.split("(?i)<(body|frame)[^>]*>", all, 1)
if len(parts) == 3:
head, void, body = parts
else:
print('Cannot split ' + path)
body = all
return re.sub("<[^>]+?>", "", re.sub(r"(?is)<(script|style|select|noscript)[^>]*>.*?</\1\s*>","", body))
except UnicodeDecodeError:
continue
print('Cannot detect encoding of ' + path)
print(exceptions)
return None
def get_title(self,path):
return re.split('\/', path)[-1]
def preprocess(self, text):
text = re.sub("&[^;]+;", " ", text)
text = mojimoji.han_to_zen(text, digit=False)
text = re.sub('(\s| |#)+', " ", text)
return text
Im Standard-IPA-Wörterbuch wird "künstliche Intelligenz" in zwei Wörter wie "künstliche" und "Intelligenz" zerlegt. Daher habe ich den Begriff, den ich als ein Wort verwenden möchte, in user_dic.csv registriert und versucht, ihn von janome aus zu verwenden.
danach,
mecab-ipadic-NEologd : Neologism dictionary for MeCab Wikipedia- und Hatena-Wörter zum Wörterbuch von mecab in Ubuntu 14.04 hinzugefügt Generieren und verwenden Sie ein Benutzerwörterbuch aus Wikipedia- und Hatena-Schlüsselwörtern für die morphologische Analyse
Ich habe es auch gefunden, aber ich habe es noch nicht ausprobiert, da es nach dem Wechsel zur Richtlinie zur Verwendung von thesaurus.csv war.
(3) thesaurus
Wie später beschrieben wird, fiel Ratlosigkeit beim Extrahieren von Token mithilfe der japanischen Bibliothek für morphologische Analysen nicht in den zulässigen Bereich, und die Themenextraktion funktionierte nicht. Daher enthält thesaurus.csv etwa 350 Wörter, die häufig im Voraus von Hand in künstlicher Intelligenz vorkommen.
thesaurus.csv(Beispiel)
Verarbeitung natürlicher Sprache,NLP,Natural Language Processing,natural language processing
Frage Antwort
Spracherkennung
AlphaGo,Alpha Go
…
Der Prozess des Registrierens und Ausschneidens nur der Trefferwörter als Token,
thesaurus.py
import re
import mojimoji
class Thesaurus:
def __init__(self,path):
map = dict()
with open(path, 'r') as thesaurus:
for line in thesaurus.readlines():
words = [mojimoji.han_to_zen(word, digit=False) for word in re.split(',', line.strip())]
for word in words:
if word in map:
print('Word duplicated: ' + word)
raise
map[word] = words[0]
self.words = map
self.re = re.compile("|".join(sorted(map.keys(), key=lambda x: -len(x))))
def tokenize(self,sentence):
for token in re.finditer(self.re, sentence):
yield(Token(self.words[token.group()]))
class Token:
def __init__(self, surface):
self.surface = surface
self.part_of_speech = "Benutzerdefinierte Nomenklatur"
Ich habe es in beschrieben und die japanische Bibliothek für morphologische Analysen ersetzt [^ 1].
article.py
import codecs
import re
import mojimoji
from thesaurus import Thesaurus
class Article:
encodings = [
"utf-8",
"cp932",
"euc-jp",
"iso-2022-jp",
"latin_1"
]
tokenizer = Thesaurus('thesaurus.csv')
def __init__(self,path):
print(path)
self.path = path
self.contents = self.preprocess(self.get_contents(path))
self.tokens = [token.surface for token in self.tokenizer.tokenize(self.contents) if re.match("Benutzerdefinierte Nomenklatur|Substantiv,(Einzigartig|Allgemeines|Sa seltsam)", token.part_of_speech)]
def get_contents(self,path):
exceptions = []
for encoding in self.encodings:
try:
all = codecs.open(path, 'r', encoding).read()
parts = re.split("(?i)<(body|frame)[^>]*>", all, 1)
if len(parts) == 3:
head, void, body = parts
else:
print('Cannot split ' + path)
body = all
return re.sub("<[^>]+?>", "", re.sub(r"(?is)<(script|style|select|noscript)[^>]*>.*?</\1\s*>","", body))
except UnicodeDecodeError:
continue
print('Cannot detect encoding of ' + path)
print(exceptions)
return None
def get_title(self,path):
return re.split('\/', path)[-1]
def preprocess(self, text):
text = re.sub("&[^;]+;", " ", text)
text = mojimoji.han_to_zen(text, digit=False)
return text
Im Themenmodell werden Sätze als BOW (Bag of Words, Liste von (Wort-ID, Anzahl der Vorkommen)) behandelt. Daher haben wir die folgenden Klassen definiert.
Attribut
articles (HTML-Dateipfad:Artikel Objekt)OrderedDictionary bestehend aus
Schlüsselliste der HTML-Dateipfade(list of string)
Größe Artikel Anzahl der Objekte
Texte Token, aus denen der Korpus besteht(list of (list of string))
Korpustexte in BOW-Liste konvertiert
Klassenmethode speichern/Es hat eine Last und ermöglicht es Ihnen, Objekte in einer Datei zu speichern.
Attribut
Training Corpus Objekt für das Training
Korpusobjekt für Testtest
dictionary training,Test Häufig verwendetes Gensim.corpora.Wörterbuchobjekt
(Wort-ID(integer)Ausgedrückt als(string)Bewahren Sie die Korrespondenz von)
corpus.py
import pickle
from collections import defaultdict
from gensim import corpora
class Corpora:
def __init__(self, training, test, dictionary):
self.training = training
self.test = test
self.dictionary = dictionary
def save(self, title):
self.training.save(title+'_training')
self.test.save(title+'_test')
self.dictionary.save(title+".dict")
@classmethod
def load(cls, title):
training = Corpus.load(title+'_training')
test = Corpus.load(title+'_test')
dictionary = corpora.Dictionary.load(title+".dict")
return cls(training, test, dictionary)
@classmethod
def generate(cls, training, test):
training_corpus = Corpus.generate(training)
test_corpus = Corpus.generate(test)
all_texts = training_corpus.texts + test_corpus.texts
frequency = defaultdict(int)
for text in all_texts:
for token in text:
frequency[token] += 1
all_texts = [[token for token in text if frequency[token] > 1] for text in all_texts]
dictionary = corpora.Dictionary(all_texts)
training_corpus.mm(dictionary)
test_corpus.mm(dictionary)
return cls(training_corpus, test_corpus, dictionary)
class Corpus:
def __init__(self, articles):
self.articles = articles
self.keys = list(articles.keys())
self.size = len(articles.keys())
def article(self, index):
return self.articles[self.keys[index]]
def mm(self, dictionary):
values_set = set(dictionary.values())
self.texts = [[token for token in text if token in values_set] for text in self.texts]
# print(self.texts[0])
self.corpus = [dictionary.doc2bow(text) for text in self.texts]
def save(self, title):
with open(title+".pickle", 'wb') as f:
pickle.dump(self.articles, f)
corpora.MmCorpus.serialize(title+".mm", self.corpus)
@classmethod
def load(cls, title):
with open(title+".pickle", 'rb') as f:
articles = pickle.load(f)
corpus = cls(articles)
corpus.corpus = corpora.MmCorpus(title+".mm")
return corpus
@classmethod
def generate(cls, articles):
corpus = cls(articles)
corpus.texts = [articles[key].tokens for key in articles.keys()]
return corpus
Bis zu diesem Punkt ist es eine Technologie, die häufig benötigt wird, unabhängig davon, was für lokale Tools verwendet wird.
Bereiten Sie den obigen Werkzeugständer vor.
Erstellen einer Anwendung mit dem Themenmodell… (* 1)
Wir klassifizierten nach Themenmodell mit Bezug auf.
test_view_LDA.py
import pprint
import logging
import glob
import numpy as np
import matplotlib.pylab as plt
from collections import OrderedDict
from gensim import corpora, models, similarities
from pprint import pprint # pretty-printer
from corpus import Corpus, Corpora
from article import Article
#logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
topic_range = range(10, 11)
training_percent = 90
test_percent = 10
path_pattern = '/home/samba/suchowan/links/bookmarks.crawled/**/*.html'
def corpus_pair(path, training_range, test_range):
all_paths = glob.glob(path, recursive=True)
training_paths = [v for i, v in enumerate(all_paths) if ((i * 2017) % 100) in training_range]
test_paths = [v for i, v in enumerate(all_paths) if ((i * 2017) % 100) in test_range ]
training_articles = OrderedDict([(path,Article(path)) for path in training_paths])
test_articles = OrderedDict([(path,Article(path)) for path in test_paths])
return Corpora.generate(training_articles, test_articles)
def calc_perplexity(m, c):
return np.exp(-m.log_perplexity(c))
def search_model(pair):
most = [1.0e15, None]
print("dataset: training/test = {0}/{1}".format(pair.training.size, pair.test.size))
for t in topic_range:
m = models.LdaModel(corpus=pair.training.corpus, id2word=pair.dictionary, num_topics=t, iterations=500, passes=10)
p1 = calc_perplexity(m, pair.training.corpus)
p2 = calc_perplexity(m, pair.test.corpus)
print("{0}: perplexity is {1}/{2}".format(t, p1, p2))
if p2 < most[0]:
most[0] = p2
most[1] = m
return most[0], most[1]
pair = corpus_pair(path_pattern, range(0, training_percent+1), range(training_percent, training_percent+test_percent+1))
pair.save('article_contents')
perplexity, model = search_model(pair)
print("Best model: topics={0}, perplexity={1}".format(model.num_topics, perplexity))
def show_document_topics(c, m, r):
# make document/topics matrix
t_documents = OrderedDict()
for s in r:
# ts = m.__getitem__(c[s], -1)
ts = m[c[s]]
max_topic = max(ts, key=lambda x: x[1])
if max_topic[0] not in t_documents:
t_documents[max_topic[0]] = []
t_documents[max_topic[0]] += [(s, max_topic[1])]
return t_documents
topic_documents = show_document_topics(pair.test.corpus, model, range(0,pair.test.size))
for topic in topic_documents.keys():
print("Topic #{0}".format(topic))
for article in topic_documents[topic]:
print(article[0], pair.test.article(article[0]).path)
pprint(model.show_topics())
Die verwendete Bibliothek war gensim und Ähnlichkeitsberechnung für Twitter-Benutzer mit tfidf, lsi, lda. / 88) und [Versuchen Sie die Verarbeitung natürlicher Sprache mit dem Python_topic-Modell](http://esu-ko.hatenablog.com/entry/2016/03/24/Python%E3%81%A7%E8%87 % AA% E7% 84% B6% E8% A8% 80% E8% AA% 9E% E5% 87% A6% E7% 90% 86% E3% 82% 92% E3% 81% 97% E3% 81% A6 % E3% 81% BF% E3% 82% 8B_% E3% 83% 88% E3% 83% 94% E3% 83% 83% E3% 82% AF% E3% 83% A2% E3% 83% 87% E3 Ich bezog mich auch auf% 83% AB). ★training
Eingang:Trainingskorpus- list of (list of (Wort-ID,Anzahl der Auftritte))Und die Anzahl der Themen
list of (Wort-ID,Anzahl der Auftritte) - 個々の article での単語のAnzahl der Auftritte (Die Reihenfolge des Auftretens wird nicht berücksichtigt)
Ausgabe:LDA-Modell- gensim.models.ldamodel
list of ((list of (Wort-ID,Anzahl der Auftritte))Formel zur Berechnung der Themenanpassungswahrscheinlichkeit aus)
★test
Eingang:Testkorpus- list of (list of (Wort-ID,Anzahl der Auftritte))
list of (Wort-ID,Anzahl der Auftritte) - 個々の article での単語のAnzahl der Auftritte (Die Reihenfolge des Auftretens wird nicht berücksichtigt)
Ausgabe: list of (Liste der Anpassungswahrscheinlichkeiten)
Ich habe versucht, ein Korpus zu erstellen und nach Themenmodellen zu klassifizieren, indem ich Wörter mit janome extrahiert und nur durch Teile der Sprache eingegrenzt habe, aber Ratlosigkeit wurde zu einem astronomischen Wert, und es ergab keinen Sinn.
Wir haben möglicherweise einige der erforderlichen Vorverarbeitungen weggelassen, aber der zugrunde liegende Grund ist klar.
Anzahl der Worttypen >> Anzahl der Dokumente
Dies.
Das Themenmodell enthält Variablen, die durch die Anzahl der Worttypen + α angepasst werden können. Eine erzwungene Konvergenz unter der Bedingung "Anzahl der Worttypen >> Anzahl der Dokumente" führt zwangsläufig zu einem Überlernen.
Anzahl der Worttypen << Anzahl der Dokumente
Sie müssen die Wörter so eingrenzen, dass
Das Folgende ist das Ergebnis der manuellen Registrierung von ungefähr 350 Wörtern, die häufig in künstlicher Intelligenz in thesaurus.csv vorkommen, und der Erstellung eines Korpus, der nur diese verwendet.
Die Anzahl der Themen ist eine Trainingseingabe. Sie können die Entscheidung jedoch automatisieren, indem Sie nach der Anzahl der Themen suchen, die die Verwirrung minimieren. Im Operationsbeispiel wurde im Voraus bestätigt, dass die Anzahl der Themen 10 beträgt und die Verwirrung minimiert wird.
Nach (* 1)
Die Umkehrung der Ratlosigkeit gibt an, inwieweit Wörter in einem Dokument vorhergesagt werden können. Der höchste Wert ist also 1. Je schlechter die Genauigkeit des Modells ist, desto größer ist der Wert (2 Ziffern sind in Ordnung, die erste Hälfte von 3 Ziffern ist in Ordnung und danach ist es schlecht, Bei einer Ziffer ist es besser, das Modell und die Berechnungsmethode der Ratlosigkeit auf Fehler zu überprüfen. Gut).
Im Ausführungsbeispiel wird 1920 Artikel (90%) für das Training verwendet, 210 Artikel (10%) für den Test [^ 2] und die Ratlosigkeit des Testkorpus beträgt 68,4.
Die Liste der Formeln zur Berechnung der Themenanpassungswahrscheinlichkeit lautet wie folgt
[(0,
'0.268*Bild+ 0.124*Dell + 0.049*CNN + 0.043*Tiefes Lernen+ 0.038*neurales Netzwerk+ '
'0.026*Maschinelles Lernen+ 0.025*Chainer + 0.024*GPU + 0.023*Artikel+ 0.022*Bilderkennung'),
(1,
'0.135*Maschinelles Lernen+ 0.121*Python + 0.102*Artikel+ 0.055*Chainer + 0.052*Dell + '
'0.037*Tiefes Lernen+ 0.033*numpy + 0.023*Rahmen+ 0.019*neurales Netzwerk+ 0.019*Spark'),
(2,
'0.111*Artikel+ 0.097*Prognose+ 0.090*Rangfolge+ 0.071*Universität+ 0.055*Suche+ 0.033*Künstliche Intelligenz+ '
'0.032*Yahoo + 0.032*Dell + 0.029*Datenbank+ 0.026*Patent'),
(3,
'0.121*Ruby + 0.100*Spiel+ 0.090*AlphaGo + 0.085*Gehen+ 0.077*Artikel+ 0.076*Künstliche Intelligenz+ '
'0.053*Google + 0.052*Microsoft + 0.047*Tay + 0.034*Twitter'),
(4,
'0.113*TensorFlow + 0.103*LSTM + 0.070*Dell + 0.068*CNN + 0.063*line + '
'0.058*Theano + 0.043*SPARQL + 0.038*Keras + 0.037*Python + 0.035*MNIST'),
(5,
'0.130*Wolke+ 0.096*Sicherheit+ 0.079*AWS + 0.079*Amazon + 0.075*Artikel+ 0.057*IoT '
'+ 0.042*Große Daten+ 0.031*Bücher+ 0.023*Attacke+ 0.022*IBM'),
(6,
'0.177*Google + 0.137*API + 0.100*Suche+ 0.071*Artikel+ 0.055*Facebook + '
'0.031*Watson + 0.030*IBM + 0.026*Bluemix + 0.026*Maschinelles Lernen+ 0.025*Twitter'),
(7,
'0.351*Künstliche Intelligenz+ 0.093*Roboter+ 0.064*Tiefes Lernen+ 0.049*Artikel+ 0.032*Universität+ 0.029*Maschinelles Lernen+ '
'0.020*Universität Tokio+ 0.019*Facebook + 0.019*Filme+ 0.019*Google'),
(8,
'0.188*bot + 0.180*Microsoft + 0.057*Azure + 0.056*Elasticsearch + '
'0.042*word2vec + 0.038*Maschinelles Lernen+ 0.033*line + 0.030*Suche+ 0.027*Kibana + '
'0.022*Verarbeitung natürlicher Sprache'),
(9,
'0.102*Artikel+ 0.094*Twitter + 0.079*Roboter+ 0.060*IoT + 0.058*Sony+ 0.041*Lernen stärken'
'+ 0.038*TensorFlow + 0.029*Java + 0.028*Deep\u3000Q−Network + 0.027*Rangfolge')]
Eine Ratlosigkeit von 68,4 scheint nicht so schlimm zu sein, aber wenn man diese Formel betrachtet, scheint es für das menschliche Auge ziemlich schwierig zu sein, die Bedeutung des Themas zu lesen.
Zurück im Beispiel von (* 1) als Token, das aus dem Originalartikel extrahiert wurde:
Großer Salon mit 15 oder mehr Sitzplätzen / Parkplatz verfügbar / Rezeption ist nach 19:00 Uhr in Ordnung / Ganzjährig geöffnet / Innerhalb von 3 Minuten zu Fuß vom nächsten Bahnhof / Haargarnitur / Nagel / Rezeption noch vor 10 Uhr / Getränkeservice verfügbar / Kartenzahlung OK / Viele weibliche Mitarbeiter / Privatzimmer verfügbar / Nichtraucher / Halbprivates Zimmer verfügbar
Die Erklärung wie im Beispiel in wird durch '/' geteilt. Dies ist eher ein direktes Merkmal als ein aus der natürlichen Sprache extrahiertes Token. Mit diesem lukrativen Token ist die Verwirrung über die beiden Themen 17.1, daher denke ich nicht, dass dieses Beispiel zu ungeschickt war. Umgekehrt kann es bei einem Datensatz mit Skalierung und Inhalt wie diesem Beispiel schwierig sein, eine auffällige unbeaufsichtigte Klassifizierung mit einem Themenmodell vorzunehmen.
Wenn Verbesserungen möglich sind, können die folgenden Punkte berücksichtigt werden.
-Extrahieren Sie den wahren Text mit Webstemmer. ・ Tuneup von thesaurus.csv
Für letztere weiß ich jedoch nicht, wozu die Automatisierung dient, indem die Synonyme manuell gepflegt werden. Wenn neue Unternehmen in die Branche des maschinellen Lernens eintreten, müssen sie sich entscheiden und sie zu thesaurus.csv hinzufügen.
Das kürzlich angekündigte JUMAN ++
Soweit ich gelesen habe, mag es bei der Lösung des Problems effektiv sein, aber es ist eine zukünftige Aufgabe.
[^ 1]: Iteratoren usw. sind so implementiert, dass sie dieselbe API haben.
[^ 2]: Zum Zeitpunkt dieser Umfrage gab es ungefähr 2000 Artikel, aber jetzt sind es ungefähr 5000 Artikel.
Recommended Posts