エイエイレトリック

なぐりがき

# spacy 日本語モデルにおける Token.morph

Spacy V3.0 から追加された Token の morph について日本語は他と仕様が違うようだったので調べました。

動作確認は google colab。 コードは Gist にアップロードしています。

spacy   3.7.5
en-core-web-sm  3.7.1
ja-core-news-sm 3.7.0

ドキュメント

Token のattributes には Morphological analysis. とだけ記載。

MorphAnalysis によると CoNLL-U Format の Morphological Annotation の情報が辞書で入っています。

英語モデルの morph

まずは英語のモデル en_core_web_sm で確認。

上記ドキュメントとdiscussions に書いてある通り、 morph には Universal features の情報が入っています。

実際に結果をみてみます。

import spacy

nlp = spacy.load("en_core_web_sm")
text = ("When Sebastian Thrun started working on self-driving cars at "
        # 省略
        "this week.")
doc = nlp(text)

for token in doc:
    print(token.text, token.pos_, token.tag_, token.morph.to_dict())

単語によって morph に含まれる情報は異なります。

たとえば動詞の場合は時制 (Tense)・動詞派生語 (VerbForm) を含むことが多い。

When {}
Sebastian {'Degree': 'Pos'}
Thrun {'Number': 'Sing'}
started {'Tense': 'Past', 'VerbForm': 'Fin'}
working {'Aspect': 'Prog', 'Tense': 'Pres', 'VerbForm': 'Part'}
on {}

名詞の場合、 格 (Case) や 数 (Number, 単数・複数などの情報) を含む。

I PRON PRP {'Case': 'Nom', 'Number': 'Sing', 'Person': '1', 'PronType': 'Prs'}
can AUX MD {'VerbForm': 'Fin'}
tell VERB VB {'VerbForm': 'Inf'}
you PRON PRP {'Person': '2', 'PronType': 'Prs'}

morph の特定の情報だけ取得したい場合は get を使います。

返却値は リスト なので扱いに注意が必要です。 該当の key がない場合は None ではなく空のリストを返却します。

doc[1].morph.get("Number"), doc[2].morph.get("Number")

([], ['Sing'])

日本語モデル

日本語の morph も v3.2 から対応しているようなので確認。

https://github.com/explosion/spaCy/releases/tag/v3.2.0

Japanese reading and inflection from sudachipy are annotated as Token.morph features.

ja_nlp = spacy.load("ja_core_news_sm")

# https://ja.wikipedia.org/wiki/SpaCy
ja_text = (
    "spaCyは高度な自然言語処理を行うためプログラミング言語"
    "PythonとCythonで書かれたオープンソースソフトウェア・ライブラリである。"
)
ja_doc = ja_nlp(ja_text)

for token in ja_doc:
    print(token.text, token.pos_, token.tag_, token.morph.to_dict())

日本語モデル ja_core_news_* では、 morph に形態素解析器 sudachipy の結果を格納しています。

Python NOUN 名詞-固有名詞-一般 {'Reading': 'パイソン'}
と ADP 助詞-格助詞 {'Reading': 'ト'}
Cython NOUN 名詞-普通名詞-一般 {'Reading': 'cython'}
で ADP 助詞-格助詞 {'Reading': 'デ'}
書か VERB 動詞-一般 {'Inflection': '五段-カ行;未然形-一般', 'Reading': 'カカ'}
れ AUX 助動詞 {'Inflection': '助動詞-レル;連用形-一般', 'Reading': 'レ'}
た AUX 助動詞 {'Inflection': '助動詞-タ;連体形-一般', 'Reading': 'タ'}
オープン NOUN 名詞-普通名詞-サ変形状詞可能 {'Reading': 'オープン'}
ソース NOUN 名詞-普通名詞-一般 {'Reading': 'ソース'}
ソフトウェア NOUN 名詞-普通名詞-一般 {'Reading': 'ソフトウェア'}
・ SYM 補助記号-一般 {'Reading': '・'}

基本的にはどの token にも読み (Reading) があります。

また、活用する単語 (動詞、助動詞など) は活用 (Inflection) が含まれています。

これらはそれぞれ sudachipy における Morpheme.reading()Morpheme.part_of_speech() と対応しているようです。

Morpheme.part_of_speech() の品詞 (pos) は tag_ に入っているので、 それ以外を morph に格納したのだと思われます。

活用

活用は Unidic における 活用型 (cType) と活用形 (cForm) を ; で連結しています。 どちらかだけ使いたい時は ; で split すればよいです。

inflection = ja_doc[3].morph.get("Inflection")
print(inflection)
if inflection:
  ctype, cform = inflection[0].split(";")
  print(f"ctype: {ctype}, cform: {cform}")

['助動詞-ダ;連体形-一般']
ctype: 助動詞-ダ, cform: 連体形-一般

活用型・活用形の定義については

に詳細が記載されています。ちなみにどちらもPDFです。

比較的細かく分類されているので、ルールベースで取得したいときは定義を確認することをおすすめします。

例えば活用形の終止形は 終止形-一般 以外に 終止形-撥音便終止形-促音便 などのケースを含め6種類あります。 (下記図参照)

# 終止形の判定方法
is_end = cform.startswith("終止形")
# or 
is_end = cform.split("-")[0] == "終止形"

『形態論情報規定集(下)』より

Gist

spacy_morph_ja.ipynb