はじめまして、データサイエンティストのますみです!
宮沢賢治の「銀河鉄道の夜」に自然言語処理(Natural Language Processing; NLP)の一分野である形態素解析(Morphological Analysis)を行ってみた記事です。
今回は、”MeCab“と”Janome“という二つのツールを比較しました。
【IT用語辞典より】
例えば、「東京で週末を過ごす」という文章があった時、以下のように分割することができ る。
- 東京:固有名詞・地名
- で:格助詞
- 週末:普通名詞
- を:格助詞
- 過ごす:動詞・サ行五段・終止形
実行環境
Type | Version |
---|---|
OS | macOS Mojave v10.14.6 |
python | v3.7.3 |
mecab-python3 | v0.996.3 |
janome | v0.3.10 |
1. 前処理 / Preprocessing
1-a. 文章の読み込み
まずは、「銀河鉄道の夜」を青空文庫のサイトからテキストデータとして保存します。宮沢賢治さんは1933年に亡くなられており、国際的な基準である70年(日本の場合50年)を過ぎていてパブリックドメインとなっているため、公開されているのだと思います。
参考 銀河鉄道の夜 – 青空文庫「銀河鉄道の夜」のダウンロードページまずは、pythonで以下のようにtxtファイルを読み込んでいきましょう。
ここでは、the_night_of_the_milky_way_train.txt
という名前のファイルにして保存されています。
with open("the_night_of_the_milky_way_train.txt", mode="r", encoding="utf-8") as f:
milky_original = f.read()
print(milky_original)
# Output
# 「ではみなさんは、そういうふうに川だと云《い》われたり、乳の流れたあとだと云われたりしていたこのぼんやりと白いものがほんとうは何かご承知ですか。」先生は、黒板に吊《つる》した大きな黒い星座の図の、上から下へ白くけぶった銀河帯のようなところを指《さ》しながら、みんなに問《とい》をかけました。
# カムパネルラが手をあげました。それから四五人手をあげました。ジョバンニも手をあげようとして、急いでそのままやめました。たしかにあれがみんな星だと、いつか雑誌で読んだのでしたが、このごろはジョバンニはまるで毎日教室でもねむく、本を読むひまも読む本もないので、なんだかどんなこともよくわからないという気持ちがするのでした。
# ところが先生...
1-b. 文章の前処理
次に、ルビや改行などを削除する前処理を行っていきましょう。
ここでは、import re
というコマンドでパッケージを用いています。
import re
with open("the_night_of_the_milky_way_train.txt", mode="r", encoding="utf-8") as f:
milky_original = f.read()
milky = re.sub("《[^》]+》", "", milky_original)
milky = re.sub("[[^]]+]", "", milky)
milky = re.sub("[| 「」\n]", "", milky)
print(milky)
# Output
# ではみなさんは、そういうふうに川だと云われたり、乳の流れたあとだと云われたりしていたこのぼんやりと白いものがほんとうは何かご承知ですか。先生は、黒板に吊した大きな黒い星座の図の、上から下へ白くけぶった銀河帯のようなところを指しながら、みんなに問をかけました。カムパネルラが手をあげました。それから四五人手をあげました。ジョバンニも手をあげようとして、急いでそのままやめました。たしかにあれがみんな星だと、いつか雑誌で読んだのでしたが、このごろはジョバンニはまるで毎日教室でもねむく、本を読むひまも読む本もないので、なんだかどんなこともよくわからないという気持ちがするのでした。ところが先生は...
1-c. Pickleの生成
最後に、これらのデータをpickleに格納しましょう。
pickleはPythonオブジェクトの直列化(シリアライズ)や非直列化(デシリアライズ)を扱うライブラリです。
【Samurai Blogより】
import re
import pickle
with open("the_night_of_the_milky_way_train.txt", mode="r", encoding="utf-8") as f:
milky_original = f.read()
milky = re.sub("《[^》]+》", "", milky_original)
milky = re.sub("[[^]]+]", "", milky)
milky = re.sub("[| 「」\n]", "", milky)
with open("the_night_of_the_milky_way_train.pickle", mode="wb") as f:
pickle.dump(milky, f)
2. MeCab
【京都大学情報学研究科 (2006)より】
2-a. MeCab入門
まずは、pickleを読み込み、簡易的なMaCabの形態素解析を行ってみましょう。定性的に分離できていることが確認できます。
import MeCab as mecab
import pickle
with open("the_night_of_the_milky_way_train.pickle", mode="rb") as f:
milky = pickle.load(f)
m_tagger = mecab.Tagger()
result = m_tagger.parse(milky)
print(result)
# Output
# では 接続詞, *, *, *, *, *, では, デハ, デワ
# みなさん 名詞, 代名詞, 一般, *, *, *, みなさん, ミナサン, ミナサン
# は 助詞, 係助詞, *, *, *, *, は, ハ, ワ
# 、 記号, 読点, *, *, *, *, 、, 、, 、
# そういう 連体詞, *, *, *, *, *, そういう, ソウイウ, ソーユウ
# ふう 名詞, 非自立, 形容動詞語幹, *, *, *, ふう, フウ, フー
# に 助詞, 副詞化, *, *, *, *, に, ニ, ニ
# 川 名詞, 一般, *, *, *, *, 川, カワ, カワ
# だ 助動詞, *, *, *, 特殊・ダ, 基本形, だ, ダ, ダ
# と 助詞, 格助詞, 引用, *, *, *, と, ト, ト
# 云わ 動詞, 自立, *, *, 五段・ワ行促音便, 未然形, 云う, イワ, イワ
# れ 動詞, 接尾, *, *, 一段, 連用形, れる, レ, レ
# たり 助詞, 並立助詞, *, *, *, *, たり, タリ, タリ
# 、 記号, 読点, *, *, *, *, 、, 、, 、
# ...
2-b. Part of Speechの計算(MeCab)
Part of Speechとは、各品詞のことを表します。ここでは、名詞のみを抽出し、その個数を算出してみましょう。
import MeCab as mecab
import pickle
import numpy as np
with open("the_night_of_the_milky_way_train.pickle", mode="rb") as f:
milky = pickle.load(f)
m_tagger = mecab.Tagger()
result = m_tagger.parse(milky)
print(result)
part_of_speech = '名詞'
noun_list = []
m_parse = m_tagger.parseToNode(milky)
while m_parse:
if m_parse.feature.split(',')[0] == part_of_speech:
noun_list.append(m_parse.surface)
m_parse = m_parse.next
print(noun_list)
print(len(noun_list))
# ['みなさん', 'ふう', '川', '乳', 'あと', 'ぼんやり', 'もの', 'ほんとう', '何', '承知', '先生', '黒板', '星座', '図', '上', '下', '銀河', '帯', 'よう', 'ところ', 'みんな', '問', 'カムパネルラ', '手', 'それ', '四', '五', '人', '手', 'ジョバンニ', '手', 'あれ', 'みんな', '星', 'いつか', '雑誌', 'の', 'このごろ', 'ジョバンニ', '毎日', '教室', '本', 'ひま', '本' ...]
# 5895
合計5895個あることがわかりました。
何個か誤ってしまっているところがありますが、大まかには妥当そうですね。
3. Janome
【Janome v0.3 documentation (ja)より】
3-a. Janome入門
こちらでも同様に、pickleを読み込み、簡易的なJanomeの形態素解析を行ってみましょう。定性的に分離できていることが確認できます。
import pickle
from janome.tokenizer import Tokenizer
with open("the_night_of_the_milky_way_train.pickle", mode="rb") as f:
milky = pickle.load(f)
t = Tokenizer()
for token in t.tokenize(milky):
print(token)
# Output
# では 接続詞, *, *, *, *, *, では, デハ, デワ
# みなさん 名詞, 代名詞, 一般, *, *, *, みなさん, ミナサン, ミナサン
# は 助詞, 係助詞, *, *, *, *, は, ハ, ワ
# 、 記号, 読点, *, *, *, *, 、, 、, 、
# そういう 連体詞, *, *, *, *, *, そういう, ソウイウ, ソーユウ
# ふう 名詞, 非自立, 形容動詞語幹, *, *, *, ふう, フウ, フー
# に 助詞, 副詞化, *, *, *, *, に, ニ, ニ
# 川 名詞, 一般, *, *, *, *, 川, カワ, カワ
# だ 助動詞, *, *, *, 特殊・ダ, 基本形, だ, ダ, ダ
# と 助詞, 格助詞, 引用, *, *, *, と, ト, ト
# 云わ 動詞, 自立, *, *, 五段・ワ行促音便, 未然形, 云う, イワ, イワ
# れ 動詞, 接尾, *, *, 一段, 連用形, れる, レ, レ
# たり 助詞, 並立助詞, *, *, *, *, たり, タリ, タリ
# 、 記号, 読点, *, *, *, *, 、, 、, 、
# ...
3-b. Part of Speechの計算(Janome)
ここでも、名詞のみを抽出し、その個数を算出してみましょう。
from janome.tokenizer import Tokenizer
from janome.analyzer import Analyzer
from janome.tokenfilter import *
from janome.charfilter import *
import pickle
with open("the_night_of_the_milky_way_train.pickle", mode="rb") as f:
milky = pickle.load(f)
t = Tokenizer()
for token in t.tokenize(milky):
print(token)
part_of_speech = '名詞'
char_filters = [UnicodeNormalizeCharFilter(), RegexReplaceCharFilter(
r"[IiⅠi?.*/~=()〝 <>::《°!!!?()-]+", "")]
token_filters = [POSKeepFilter([part_of_speech]), POSStopFilter(
[]), LowerCaseFilter()]
analyzer = Analyzer(char_filters, t, token_filters)
noun_list = [token.surface for token in analyzer.analyze(milky)]
print(noun_list)
print(len(noun_list))
# ['みなさん', 'ふう', '川', '乳', 'あと', 'ぼんやり', 'もの', 'ほんとう', '何', '承知', '先生', '黒板', '星座', '図', '上', '下', '銀河', '帯', 'よう', 'ところ', 'みんな', '問', 'カムパネルラ', '手', 'それ', '四', '五', '人', '手', 'ジョバンニ', '手', 'あれ', 'みんな', '星', 'いつか', '雑誌', 'の', 'このごろ', 'ジョバンニ', '毎日', '教室', '本', 'ひま', '本' ...]
# 5895
合計5895個あることがわかりました。
MeCabと同じ個数なことがわかりました。
4. その他の品詞の解析
名詞以外のPart of Speechについても解析したところ、以下のよう結果になりました。
4-a. MeCab(その他の品詞)
Part of Speech | Length | Head Data |
---|---|---|
動詞 | 3149 | [‘云わ’, ‘れ’, ‘流れ’, ‘云わ’, ‘れ’, ‘し’, ‘い’, ‘吊し’, ‘けぶっ’, ‘指し’ …] |
形容詞 | 479 | [‘白い’, ‘黒い’, ‘白く’, ‘ねむく’, ‘ない’, ‘早く’, ‘よく’, ‘よし’, ‘白い’, ‘いい’ …] |
副詞 | 867 | [‘そのまま’, ‘たしかに’, ‘まるで’, ‘なんだか’, ‘よく’, ‘もう’, ‘はっきり’, ‘すっと’, ‘もう’ …] |
助詞 | 6356 | [‘は’, ‘に’, ‘と’, ‘たり’, ‘の’, ‘と’, ‘たり’, ‘て’, ‘と’, ‘が’, ‘は’, ‘か’, ‘か’, ‘は’, ‘に’, ‘の’, ‘の’, ‘から’ …] |
助動詞 | 2572 | ‘だ’, ‘た’, ‘だ’, ‘た’, ‘です’, ‘た’, ‘た’, ‘な’, ‘まし’, ‘た’, ‘まし’, ‘た’, ‘まし’, ‘た’, ‘う’, ‘まし’ …] |
4-b. Janome(その他の品詞)
Part of Speech | Length | Head Data |
---|---|---|
動詞 | 3148 | [‘云わ’, ‘れ’, ‘流れ’, ‘云わ’, ‘れ’, ‘し’, ‘い’, ‘吊し’, ‘けぶっ’, ‘指し’…] |
形容詞 | 479 | [‘白い’, ‘黒い’, ‘白く’, ‘ねむく’, ‘ない’, ‘早く’, ‘よく’, ‘よし’, ‘白い’, ‘いい’ …] |
副詞 | 867 | [‘そのまま’, ‘たしかに’, ‘まるで’, ‘なんだか’, ‘よく’, ‘もう’, ‘はっきり’, ‘すっと’, ‘もう’ …] |
助詞 | 6350 | [‘は’, ‘に’, ‘と’, ‘たり’, ‘の’, ‘と’, ‘たり’, ‘て’, ‘と’, ‘が’, ‘は’, ‘か’, ‘か’, ‘は’, ‘に’, ‘の’, ‘の’, ‘から’ …] |
助動詞 | 2572 | [‘だ’, ‘た’, ‘だ’, ‘た’, ‘です’, ‘た’, ‘た’, ‘な’, ‘まし’, ‘た’, ‘まし’, ‘た’, ‘まし’, ‘た’, ‘う’, ‘まし’ …] |
様々な品詞で解析を行うと、少しずつ結果が違うことがわかりました。
最後に
いかがだったでしょうか?
この記事を通して、少しでもあなたの困りごとが解決したら嬉しいです^^
📩 仕事の相談はこちら 📩
お仕事の相談のある方は、下記のフォームよりお気軽にご相談ください。
問い合わせフォームはこちら
もしもメールでの問い合わせの方がよろしければ、下記のメールアドレスへご連絡ください。
info*galirage.com(*を@に変えてご送付ください)
🎁 「生成AIの社内ガイドライン」PDFを『公式LINE』で配布中 🎁
「LINEで相談したい方」や「お問い合わせを検討中の方」は、公式LINEでご連絡いただけますと幸いです。
(期間限定で配信中なため、ご興味ある方は、今のうちに受け取りいただけたらと思います^^)
公式LINEはこちら
🚀 新サービス開始のお知らせ 🚀
新サービス 「AI Newsletter for Biz」 がスタートしました!
ビジネスパーソン向けに「AIニュース」を定期配信する完全無料のニュースレターです📩
ますみが代表を務める「株式会社Galirage」では、「生成AIを用いたシステムの受託開発(アドバイス活動含む)」をしています。
そこでお世話になっているお客様に対して、「最新トレンドを加味したベストな提案」をするために、日々最新ニュースを収集する仕組みを構築していました。
今回は、そこで構築した仕組みを活用して、より多くの人に有益な情報を届けたいと思い、本サービスを開始しました!
一人でも多くの方にとって、「AI人材としてのスキルアップ」につながれば幸いです^^
▼ 登録はこちらから ▼
https://bit.ly/ai_newsletter_for_biz_ai_lab
よければ、fugashi+unidic-liteや、sudachipyとも較べてみると、面白い結果になるかもしれません。
コメントありがとうございます!
ぜひやってみます!
こういうツールを横断的に解析するのって面白いですね:)
>>参考リンク
– SudachiPy (https://pypi.org/project/SudachiPy/)
– fugashi (https://pypi.org/project/fugashi/)
– unidic-lite (https://pypi.org/project/unidic-lite/)