テキストの類似度を求める機械学習をするには単語に分ける必要があります。
英語などであればスペースで簡単に分けることができますが、日本語だとそういうわけにはいきません。
そこでjanomeまたはmecabを使って日本語の分割をしてみます。
janomeはインストールが簡単だけれども遅い、mecabはインストールが難しいけれども速いとのことです。
以下では実際に試してみます。
インストール作業は環境により異なるためこの記事では触れません。
1.janome
(1)テキストの準備
WikipediaのAPIを使ってランダムに記事本文を取得する – 浅野直樹の学習日記でやったことを関数にしました。
import requests
def get_ml_article():
#記事ページIDの設定
page_id = "185375"
#wikipediaに接続するための基本設定
S = requests.Session()
URL = "https://ja.wikipedia.org/w/api.php"
#記事本体を取得するためのパラメータの設定
ARTICLE_PARAMS = {
"action": "query",
"format": "json",
"prop": "extracts",
"explaintext": True,
"exsectionformat": "plain",
"pageids": page_id
}
#ページIDから記事情報の取得
ARTICLE_R = S.get(url=URL, params=ARTICLE_PARAMS)
ARTICLE_DATA = ARTICLE_R.json()
return ARTICLE_DATA["query"]["pages"][page_id]["extract"]
ml_article = get_ml_article()
print(ml_article)
これで機械学習 – Wikipediaのページの記事本文が取得できました。
(2)単純に分かち書き
from janome.tokenizer import Tokenizer
t = Tokenizer(wakati=True)
words = t.tokenize(ml_article)
print(list(words))
これだけです。
['機械', '学習', '(', 'きか', 'い', 'がく', 'しゅう', '、', '英', ':', ' ', 'Machine', ' ', 'Learning', ')', 'と', 'は', '、', '経験',
【以下略】
ともかく分割はできています。
(3)出現回数のカウント
from janome.analyzer import Analyzer
from janome.tokenfilter import *
a = Analyzer(token_filters=[TokenCountFilter(sorted=True)])
words_count = a.analyze(ml_article)
print(list(words_count))
tokenizerの代わりにanalyzerを使います。
[(' ', 427), ('の', 278), ('を', 235), ('、', 216), ('。', 167), ('は', 159), ('で', 146), ('y', 143), ('学習', 137), ('\n ', 130)
【以下略】
出現回数を取得できました。
(4)不要な文字列の除去
「\n」は改行を表わす特殊文字なので除去したいです。スペースも同様です。
「の」や「を」などの助詞、「、」と「。」の句読点はここでは残しておきます(機械学習の直前でストップワードとして除去します)。
from janome.analyzer import Analyzer
from janome.charfilter import *
from janome.tokenfilter import *
char_filters = [UnicodeNormalizeCharFilter(), RegexReplaceCharFilter("\n|\s", "")]
token_filters = [TokenCountFilter(sorted=True)]
a = Analyzer(char_filters=char_filters, token_filters=token_filters)
words_count_cleaned = a.analyze(ml_article)
print(list(words_count_cleaned))
正規表現で改行文字とスペースを除去しています。
[('の', 278), ('を', 235), ('、', 214), ('。', 164), ('は', 159), ('で', 146), ('学習', 137), ('に', 127), ('y', 127), ('(', 121), ('が', 119)
【以下略】
うまくいきました。
2.mecab
お次はmecabです。
私の環境ではmecab-python3 · PyPIに書いてある2行のpipだけでインストールできました。
pip install mecab-python3
pip install unidic-lite
登場回数順にカウントするところまで一気にやります。
import MeCab
from collections import Counter
tagger = MeCab.Tagger("-Owakati")
wakati = tagger.parse(ml_article)
print(Counter(wakati.split()).most_common())
以下のように出力されます。
[('の', 290), ('を', 238), ('、', 221), ('に', 194), ('}', 190), ('。', 167), ('は', 162), ('と', 154), ('で', 151), ('y', 143), ('学習', 137),
【以下略】
先ほどのjanomeのときと微妙に数字が違いますね。何も意識せずとも「\n」やスペースは除去されていました。
3.janomeとmecabの速度比較
timeitモジュールを使います。
import requests
from janome.analyzer import Analyzer
from janome.charfilter import *
from janome.tokenfilter import *
import MeCab
from collections import Counter
from timeit import timeit
def get_ml_article():
#記事ページIDの設定
page_id = "185375"
#wikipediaに接続するための基本設定
S = requests.Session()
URL = "https://ja.wikipedia.org/w/api.php"
#記事本体を取得するためのパラメータの設定
ARTICLE_PARAMS = {
"action": "query",
"format": "json",
"prop": "extracts",
"explaintext": True,
"exsectionformat": "plain",
"pageids": page_id
}
#ページIDから記事情報の取得
ARTICLE_R = S.get(url=URL, params=ARTICLE_PARAMS)
ARTICLE_DATA = ARTICLE_R.json()
return ARTICLE_DATA["query"]["pages"][page_id]["extract"]
def janome():
char_filters = [UnicodeNormalizeCharFilter(), RegexReplaceCharFilter("\n|\s", "")]
token_filters = [TokenCountFilter(sorted=True)]
a = Analyzer(char_filters=char_filters, token_filters=token_filters)
words_count_cleaned = a.analyze(ml_article)
def mecab():
tagger = MeCab.Tagger("-Owakati")
wakati = tagger.parse(ml_article)
words_count = Counter(wakati.split()).most_common()
#機械学習 – Wikipediaのページの記事本文を取得
ml_article = get_ml_article()
#timeitで繰り返す回数を設定
loop = 100
#timeitの実行
janome_result = timeit('janome()', globals=globals(), number=loop)
mecab_result = timeit('mecab()', globals=globals(), number=loop)
#実行1回あたりの所要時間の秒数を表示
print("janome:", janome_result / loop)
print("mecab:", mecab_result / loop)
結果は次の通りになりました。
janome: 1.0871145177900325
mecab: 0.025085185560019454
mecabのほうが圧倒的に速いです。
jupyter notebookの%timeitマジックコマンドでも計測してみます。
%timeit -n 10 janome()
1.1 s ± 50.7 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit -n 10 mecab()
20.2 ms ± 907 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
結果はほぼ同じですね。janomeだと約1秒、mecabだと0.1秒以下です。
4.まとめ
速度に関してはmecabの圧勝でした。
janomeにはいろいろと気の利いた機能が備わっていることと、mecabのインストールが思っていたよりはるかに簡単だったのが印象的でした。
janomeもmecabも素晴らしいツールです。