spaCyで英語の文をトークナイズする方法を丁寧に

はじめに

本記事では,spaCyを用いて英文をトークナイズする方法を紹介します.

トークナイズに関する情報を比較的詳しく解説するとともに,公式ドキュメントやソースコードへの導線を張ることを目的にしています.

本記事に書いてあることは,公式ドキュメントの以下のページに書いてあることとほとんど変わりません.公式ドキュメントほど信頼性が高いものはありませんので,先にこちらを読まれるのをお勧めします.

Linguistic Features · spaCy Usage Documentation

目次

モジュールのインポート

インポートは一行です.

import spacy

モデルの作成

まずは,トークナイズを行うモデルを読み込みます.これはspacy.load(モデル名)で書けます.今回は英文を対象とするので,英語のモデルとして一般的に使われているen_core_web_smを読み込んでいます.

import spacy
nlp = spacy.load('en_core_web_sm')

もしエラーが出る場合は,en_core_web_smのモデルがインストールされていないので,

python -m spacy download en_core_web_sm

でインストールしてください.

モデルは英語以外にも用意されています.各言語に対応するモデルは以下の公式ドキュメントを参考にしてください.

Models · spaCy Models Documentation

英文のトークナイズとDocオブジェクト

読み込んだモデルは関数のように扱うことができます.入力は文字列で,出力はspaCy独自のDocオブジェクトになります.

Docオブジェクトの詳細: Doc · spaCy API Documentation

import spacy
nlp = spacy.load('en_core_web_sm')

sent = "I don't like apple."
doc = nlp(sent)
print(type(doc))
'''
出力:
<class 'spacy.tokens.doc.Doc'>
'''

Docオブジェクトは,トークナイズ後の単語列に関する情報が含まれていて,リストのような振る舞いをします.例えば,0番目を参照すると,先頭単語に関する情報が得られます.よって,一般的なリストのように,indexによる参照と,for文による先頭単語からの参照が可能です.

import spacy
nlp = spacy.load('en_core_web_sm')

sent = "I don't like apple."
doc = nlp(sent)
# for文で参照
for token in doc:
    print(type(token), token)

# indexで参照
print(doc[0])
'''
出力:
<class 'spacy.tokens.token.Token'> I
<class 'spacy.tokens.token.Token'> do
<class 'spacy.tokens.token.Token'> n't
<class 'spacy.tokens.token.Token'> like
<class 'spacy.tokens.token.Token'> apple
<class 'spacy.tokens.token.Token'> .
I
'''

このように参照したオブジェクトは,print()するとトークナイズ後の単語がそのまま出力されます.上の例では,don't → do n'tapple. → apple .のようにトークナイズされていることが分かります.ただし,型は文字列ではなく,spaCy独自のTokenオブジェクトになります.

よって,単にトークナイズ後の表層系だけ欲しい場合は

import spacy

def tokenizer(nlp, sent):
    doc = nlp(sent)
    return ' '.join([tok.text for tok in doc])

nlp = spacy.load('en_core_web_sm')
sent = "I don't like apple."
print(tokenizer(nlp, sent))
'''
出力:
I do n't like apple .
'''

のように多少自作しなければなりません..textについては次の節で説明します.

Tokenオブジェクトの機能

spaCy独自のTokenオブジェクトは,様々な情報を持っています.単語を表す文字列の情報はもちろん,その単語の品詞や係り受けなどの情報を持ちます.

以下では公式ドキュメントが紹介している代表的な属性を紹介します.

import spacy
nlp = spacy.load('en_core_web_sm')

sent = "I don't like apple."
doc = nlp(sent)

# 3番目のトークン
token = doc[2]
print('.text:    ', token.text, type(token.text), sep='\t')
print('.lemma_:  ', token.lemma_, type(token.lemma_), sep='\t')
print('.pos_:    ', token.pos_, type(token.pos_), sep='\t')
print('.tag_:    ', token.tag_, type(token.tag_), sep='\t')
print('.dep_:    ', token.dep_, type(token.dep_), sep='\t')
print('.shape:   ', token.shape_, type(token.shape_), sep='\t')
print('.is_alpha:', token.is_alpha, type(token.is_alpha), sep='\t')
print('.is_stop: ', token.is_stop, type(token.is_stop), sep='\t')
'''
出力:
.text:          n't     <class 'str'>
.lemma_:        not     <class 'str'>
.pos_:          ADV     <class 'str'>
.tag_:          RB      <class 'str'>
.dep_:          neg     <class 'str'>
.shape:         x'x     <class 'str'>
.is_alpha:      False   <class 'bool'>
.is_stop:       False   <class 'bool'>
'''
  • .textは,単語そのものです.

  • .lemma_は,単語の原形です.例えば,go, went, goingのlemmaは全てgoです.

  • .pos_は,品詞です.詳しくは.pos_の品詞タグ早見表の節で説明しますが,17種類あります.

  • .tag_ は,より詳細な品詞です.例えば,.pos_では単にNOUN(名詞)と表されるものが,.tag_ではNNS(複数形の名詞)のように表されるようなことです.タグの一覧は以下を参照してください.

    spaCy/tag_map.py at 3ddb799f27578d3eed39ded12fc812609106b26c · explosion/spaCy · GitHub

  • .dep_は,構文の依存関係を表します.詳しくは構文依存関係についての節を参照してください.

  • .shape_は,単語の形を表します.具体的には,各文字について,大文字はX,小文字はx,数字はdに変換して表示します.記号はそのままです.例えば,aA2'!$#&%xXd'!$#&%となります.

  • .is_alphaは,単語がアルファベットだけで構成されているかを判定します.数字や記号が一つでも混じっているとFalseになります.

  • .is_stopは,ストップワードかどうか判定します.英語におけるストップワードの単語集合は,以下を参照してください.(他の言語についても,同じようにソースを見に行けば単語集合を得られます.)

    spaCy/stop_words.py at 3ddb799f27578d3eed39ded12fc812609106b26c · explosion/spaCy · GitHub

これ以外にもたくさんの属性が用意されています.詳しくは以下を参照してください.

Token · spaCy API Documentation

.pos_の品詞タグ早見表

品詞タグは17種類あります.Universal POS tagsを利用しています.

縦長になるので横に並列して書くことにします.

品詞タグ 意味 品詞タグ 意味
ADJ 形容詞 PART 助詞
ADP 設置詞 PRON 代名詞
ADV 副詞 PROPN 固有名詞
AUX 助動詞 PUNCT 句読点
CONJ 接続詞 SCONJ 連結詞
DET 限定詞 SYM シンボル
INTJ 間投詞 VERB 動詞
NOUN 名詞 X その他(主に未知語)
NUM 数詞

参考: Universal POS tags

.dep_: 構文依存関係について

構文依存関係は.dep_で参照できる情報で,係り受けを表すものです.例えば,動詞の目的語を特定できます.

公式ドキュメントでは明確に言及にしている記述が見つけられませんでしたが,おそらくUniversal Dependenciesを用いていると思います.これについては,数が非常に多いため,一つ一つ解説することは避けます.参考1(英語,公式),参考2(日本語,ブログ記事)を参照してください.

参考1: Universal Dependencies

参考2: 自然言語処理におけるPOSタグと係り受けタグ一覧 - Qiita

係り受け解析の可視化

係り受け解析の結果は,spaCyのモジュールdisplacyを使うことで可視化できます.このモジュールは,spaCy2.0以降に実装されています.具体的には,displacy.serve()関数を使います.入力として<class 'spacy.tokens.doc.Doc'>型のトークナイズした直後のオブジェクトを与えると,ローカルサーバの上で図が閲覧できます.

import spacy
from spacy import displacy

nlp = spacy.load('en_core_web_sm')
sent = "I don't like apple."
doc = nlp(sent)
displacy.serve(doc, style="dep")
'''
出力:
Using the 'dep' visualizer
Serving on http://0.0.0.0:5000 ...
'''

これを実行するとServing on http://0.0.0.0:5000 ...と表示されるので,ブラウザでlocalhost:5000にアクセスすると,係り受けの可視化図が閲覧できます.この図には,各単語の係り受け.dep_の情報と,その品詞.pos_の情報が含まれています.

f:id:gotutiyan:20200926184545p:plain

おわりに

今回はspaCyによる英文トークナイズについて紹介しました.思ったよりざっくりとした記事になった気もしますが,参考になれば幸いです.他に面白そうな機能を見つけたら随時更新するかもしれません.

間違いなどあればご指摘お願いいたします.