🧞
トピックモデルによる日本語テキスト分類
この記事でできるようになること
自前の文章からトピックモデル(LDA:潜在的ディリクレ配分法)を用いてテキストを分類する
教師なし学習なのでテキストを集めるだけで良く楽
Gensim
文章を意味ベクトルとして表現するためのPythonライブラリ
また、教師なし機械学習を用いてテキストを処理することができる
サンプルコードを見てみる
Gensimのサンプルコードを見てLdaModelに何を渡せばいいか調べる
from gensim.test.utils import common_texts
from gensim.corpora.dictionary import Dictionary
# Create a corpus from a list of texts
common_dictionary = Dictionary(common_texts)
common_corpus = [common_dictionary.doc2bow(text) for text in common_texts]
# Train the model on the corpus.
lda = LdaModel(common_corpus, num_topics=10)
common_textsは単語のリストのリスト
[['human', 'interface', 'computer'], ['survey', 'user', 'computer', 'system', 'response', 'time'], ['eps', 'user', 'interface', 'system'], ['system', 'human', 'system', 'eps'], ['user', 'response', 'time'], ['trees'], ['graph', 'trees'], ['graph', 'minors', 'trees'], ['graph', 'minors', 'survey']]
dictionaryは単語とIDのセット. common_texts形式を渡すと重複なしのDictionaryを作ってくれる
print(common_dictionary.token2id)
{'computer': 0, 'human': 1, 'interface': 2, 'response': 3, 'survey': 4, 'system': 5, 'time': 6, 'user': 7, 'eps': 8, 'trees': 9, 'graph': 10, 'minors': 11}
bag-of-words
単語とその出現回数で文章を表現する
common_corpus = [common_dictionary.doc2bow(text) for text in common_texts]
print(common_corpus)
[[(0, 1), (1, 1), (2, 1)], [(0, 1), (3, 1), (4, 1), (5, 1), (6, 1), (7, 1)], [(2, 1), (5, 1), (7, 1), (8, 1)], [(1, 1), (5, 2), (8, 1)], [(3, 1), (6, 1), (7, 1)], [(9, 1)], [(9, 1), (10, 1)], [(9, 1), (10, 1), (11, 1)], [(4, 1), (10, 1), (11, 1)]]
つまりデータの流れは
文章のリストの作成
ここは各タスクに依存するため、get_text_list関数として作成しておく
単語リストのリスト作成
日本語文章なので形態素解析する必要がある。
今回はPythonで手軽に形態素解析できるsudachipyを用いる
テキストの標準化
テキストから余計な情報を削除し、フォーマットを統一する
def normalize_text_list(text_list):
import pandas as pd
text_series = pd.Series(text_list)
text_series = text_series.str.normalize("NFKC") # 文字コード整形
text_series = text_series.str.lower() # 英語は小文字に統一
text_series = text_series.replace('@[0-9a-zA-Z_]{1,15}',"", regex=True) # IDを削除
text_series = text_series.replace(" ","",regex=True) # 全角スペース削除
text_series = text_series.replace(" ","",regex=True) # スペース削除
text_series = text_series.replace("\n","",regex=True) # 改行削除
return list(text_series)
text_list = get_text_list()
text_list = normalize_text_list(text_list)
sudachipyにより単語の分かち書きにする
from sudachipy import tokenizer
from sudachipy import dictionary
import re
def sudachipy_tokenizer(text):
tokenizer_obj = dictionary.Dictionary().create()
mode = tokenizer.Tokenizer.SplitMode.C
token = tokenizer_obj.tokenize(text, mode)
token_list = [t.dictionary_form() for t in token]
token_list = [t.lower() for t in token_list]
token_list = [t for t in token_list if not len(t)==1]
kana_re = re.compile("^[ぁ-ゖ]+$")
token_list = [t for t in token_list if not kana_re.match(t)]
token_list = [t for t in token_list]
return token_list
common_texts = [sudachipy_tokenizer(text) for text in text_list]
Dictionary化、bagofwordsのリスト化
単語リストのリストができてるのでここからは同じ
from gensim.corpora.dictionary import Dictionary
common_dictionary = Dictionary(common_texts)
common_corpus = [common_dictionary.doc2bow(text) for text in common_texts]
LDAにかける
分類したいトピック数に応じてnum_topicsを変更する
from gensim.models import LdaModel
lda = LdaModel(common_corpus, num_topics=4)
LDAを使って分類してみる
lda.get_document_topicsに文章のBoWを渡すことで分類できる
def get_document_topics(text, lda, dict):
text = normalize_text_list([text])
text = sudachipy_tokenizer(*text)
text = dict.doc2bow(text)
lda_result = lda.get_document_topics(text)
print(lda_result)
return max(lda_result, key=lambda x:x[1])
text = "Amazon ECSとAmazon EKSの主要なメトリクスをモニタリングする方法を学び、コンテナ化されたAWSアプリケーションを大規模に追跡するための戦略を解説しています。無料のeBookを今すぐダウンロードしてください。"
topic = get_document_topics(text, lda, common_dictionary)
print(topic) # (0, 0.62431365)
Discussion