キヨシの命題考えたこと、つくったもの。

記事

自然言語処理ライブラリspaCyが日本語対応したので試してみた

この記事の目次 5項目

spaCyという自然言語処理のためのライブラリがバージョン2.3にアップデートされ、日本語に対応しました。

Explosion
Introducing spaCy v2.3 · Explosion
https://explosion.ai/blog/spacy-v2-3/
spaCy now speaks Chinese, Japanese, Danish, Polish and Romanian! Version 2.3 of the spaCy Natural Language Processing library adds models for five new languages. We've also updated all 15 model families with word vectors and improved accuracy, while also decreasing model size and loading times for models with vectors.

このアップデートによって、ベクトルを内包するモデルのサイズやロードにかかる時間が減少し、さらに単語ベクトルの精度が向上したとのことです。

公式ドキュメントを見ると、単語のセグメンテーションと品詞タグ付けにはSudachiPyを利用しているようです。
今回は早速、spaCyを使って日本語の分かち書きや学習済み統計モデルを試してみます。
コードは以下にあげています。

GitHub
yolo-kiyoshi/spacy_sample
https://github.com/yolo-kiyoshi/spacy_sample
Contribute to yolo-kiyoshi/spacy_sample development by creating an account on GitHub.

目次

インストール方法

以下のコマンドにより日本語対応したspaCyをインストールできます。

pip install spacy[ja]

使い方

spaCyのデフォルトで扱える単語セグメンテーションと品詞タグ付け、および学習済み統計モデルを利用した単語間の類似度を算出してみます。

単語セグメンテーションと品詞タグ付け

SudachiPyの分割モードA、B、Cを使って、簡単な単語セグメンテーションと品詞タグ付けをやってみます。

デフォルトではSudachiPyの分割モードAを使用します。

from spacy.lang.ja import Japanese

# 分かち書き対象
text = '今日は炎天下の中、国会議員とjavaでコーディングしながらご飯を食べた。'
# SudachiPy with split mode A
nlp = Japanese()
for w in nlp(text):
    print(f'text:{w.text}, pos:{w.pos_}, tag:{w.tag_}, lemma:{w.lemma_}')
text:今日, pos:NOUN, tag:名詞-普通名詞-副詞可能, lemma:今日
text:は, pos:ADP, tag:助詞-係助詞, lemma:は
text:炎天, pos:NOUN, tag:名詞-普通名詞-一般, lemma:炎天
text:下, pos:NOUN, tag:接尾辞-名詞的-副詞可能, lemma:下
text:の, pos:ADP, tag:助詞-格助詞, lemma:の
text:中, pos:NOUN, tag:名詞-普通名詞-副詞可能, lemma:中
text:、, pos:PUNCT, tag:補助記号-読点, lemma:、
text:国会, pos:NOUN, tag:名詞-普通名詞-一般, lemma:国会
text:議員, pos:NOUN, tag:名詞-普通名詞-一般, lemma:議員
text:と, pos:ADP, tag:助詞-格助詞, lemma:と
text:java, pos:NOUN, tag:名詞-普通名詞-一般, lemma:Java
text:で, pos:ADP, tag:助詞-格助詞, lemma:で
text:コーディング, pos:NOUN, tag:名詞-普通名詞-一般, lemma:コーディング
text:し, pos:AUX, tag:動詞-非自立可能, lemma:する
text:ながら, pos:SCONJ, tag:助詞-接続助詞, lemma:ながら
text:ご飯, pos:NOUN, tag:名詞-普通名詞-一般, lemma:ご飯
text:を, pos:ADP, tag:助詞-格助詞, lemma:を
text:食べ, pos:VERB, tag:動詞-一般, lemma:食べる
text:た, pos:AUX, tag:助動詞, lemma:た
text:。, pos:PUNCT, tag:補助記号-句点, lemma:。

次に、SudachiPyの分割モードBを使用します。

# SudachiPy with split mode B
cfg = {"split_mode": "B"}
nlp = Japanese(meta={"tokenizer": {"config": cfg}})
for w in nlp(text):
    print(f'text:{w.text}, pos:{w.pos_}, tag:{w.tag_}, lemma:{w.lemma_}')
text:今日, pos:NOUN, tag:名詞-普通名詞-副詞可能, lemma:今日
text:は, pos:ADP, tag:助詞-係助詞, lemma:は
text:炎天下, pos:NOUN, tag:名詞-普通名詞-一般, lemma:炎天下
text:の, pos:ADP, tag:助詞-格助詞, lemma:の
text:中, pos:NOUN, tag:名詞-普通名詞-副詞可能, lemma:中
text:、, pos:PUNCT, tag:補助記号-読点, lemma:、
text:国会, pos:NOUN, tag:名詞-普通名詞-一般, lemma:国会
text:議員, pos:NOUN, tag:名詞-普通名詞-一般, lemma:議員
text:と, pos:ADP, tag:助詞-格助詞, lemma:と
text:java, pos:NOUN, tag:名詞-普通名詞-一般, lemma:Java
text:で, pos:ADP, tag:助詞-格助詞, lemma:で
text:コーディング, pos:NOUN, tag:名詞-普通名詞-一般, lemma:コーディング
text:し, pos:AUX, tag:動詞-非自立可能, lemma:する
text:ながら, pos:SCONJ, tag:助詞-接続助詞, lemma:ながら
text:ご飯, pos:NOUN, tag:名詞-普通名詞-一般, lemma:ご飯
text:を, pos:ADP, tag:助詞-格助詞, lemma:を
text:食べ, pos:VERB, tag:動詞-一般, lemma:食べる
text:た, pos:AUX, tag:助動詞, lemma:た
text:。, pos:PUNCT, tag:補助記号-句点, lemma:。

次に、SudachiPyの分割モードCを使用します。

# SudachiPy with split mode C
cfg = {"split_mode": "C"}
nlp = Japanese(meta={"tokenizer": {"config": cfg}})
for w in nlp(text):
    print(f'text:{w.text}, pos:{w.pos_}, tag:{w.tag_}, lemma:{w.lemma_}')
text:今日, pos:NOUN, tag:名詞-普通名詞-副詞可能, lemma:今日
text:は, pos:ADP, tag:助詞-係助詞, lemma:は
text:炎天下, pos:NOUN, tag:名詞-普通名詞-一般, lemma:炎天下
text:の, pos:ADP, tag:助詞-格助詞, lemma:の
text:中, pos:NOUN, tag:名詞-普通名詞-副詞可能, lemma:中
text:、, pos:PUNCT, tag:補助記号-読点, lemma:、
text:国会議員, pos:NOUN, tag:名詞-普通名詞-一般, lemma:国会議員
text:と, pos:ADP, tag:助詞-格助詞, lemma:と
text:java, pos:NOUN, tag:名詞-普通名詞-一般, lemma:Java
text:で, pos:ADP, tag:助詞-格助詞, lemma:で
text:コーディング, pos:NOUN, tag:名詞-普通名詞-一般, lemma:コーディング
text:し, pos:AUX, tag:動詞-非自立可能, lemma:する
text:ながら, pos:SCONJ, tag:助詞-接続助詞, lemma:ながら
text:ご飯, pos:NOUN, tag:名詞-普通名詞-一般, lemma:ご飯
text:を, pos:ADP, tag:助詞-格助詞, lemma:を
text:食べ, pos:VERB, tag:動詞-一般, lemma:食べる
text:た, pos:AUX, tag:助動詞, lemma:た
text:。, pos:PUNCT, tag:補助記号-句点, lemma:。

「炎天下」や「国会議員」の分割が分割モードB、Cで異なっていることを確認できました。
上記で示した以外にもTokenオブジェクトには様々なAttributeが存在します。
詳しくは公式ドキュメントをご参照ください。

学習済み統計モデルの利用

次にspaCyの学習済み日本語統計モデルを利用して、単語間の類似度を計算してみます。
今回使用するのはja_core_news_mdというニュースやメディアをもとに学習したモデルで、20,000語を300次元のベクトルとして保持しています。

まず、以下を実行してja_core_news_mdモデルをダウンロードし、jaという名前でショートリンクを作成します。

python -m spacy download ja_core_news_md
python -m spacy link ja_core_news_md ja

次に各単語をkeyに、Tokenをvalueにもつ辞書を作成します。

import spacy

nlp = spacy.load('ja')
word_dict = {}
for w in nlp(text):
    word_dict[w.text] = w

以下、単語間の類似度を計算します。

word_dict['国会'].similarity(word_dict['議員'])
0.73714477
word_dict['今日'].similarity(word_dict['国会'])
0.12613997
word_dict['java'].similarity(word_dict['国会'])
/usr/local/lib/python3.7/site-packages/ipykernel_launcher.py:1: UserWarning: [W008] Evaluating Token.similarity based on empty vectors.
  """Entry point for launching an IPython kernel.
0.0

「国会」と「議員」の類似度は高く、「今日」と「国会」の類似度は低く算出されました。
また、「java」という単語は学習済み統計モデルには存在しないため、正常な数値は算出されませんでした。

まとめ

今回はあっさりとですが日本語対応したspaCyを使ってみました。
分かち書きから学習済み統計モデルの利用までかなりお手軽な印象を受けましたが、その中でも特に、MeCabなどと比べるとインストールがものすごく容易だと感じました。