For Your ISHIO Blog

データ分析や機械学習やスクラムや組織とか、色々つぶやくブログです。

自然言語処理ライブラリspaCyを試してみた。

お恥ずかしながら、spaCyを最近知りましたので、試してみました。 spaCyは、pythonで動かす自然言語処理ライブラリです。

spacy.io

目次

spaCyとは

spaCyは、pythonで動かす自然言語処理ライブラリです。特徴は、 事前に訓練された統計モデルと単語ベクトルが付属している点です。現在33言語をサポート、8言語に対する13個の統計モデルを利用できる。TensorFlow、PyTorch、scikit-learn、Gensim、その他のPythonのAIエコシステムとシームレスに相互運用可能。現在のバージョンはv2.x。

環境

  • Python3系
  • モデルがライブラリとしてインストール可能。pipでインストール。
pip install -U spacy

対応言語・モデル

複数の言語に対応していますが、今回は英語を扱います。英語には、4つほど学習済みの畳み込みニューラルネットワークモデル(CNN)があるようです。

モデルのインポート

en_core_web_smモデルが推奨されているようなので、デフォルトのまま利用します。

import spacy

# 英語のtokenizer、tagger、parser、NER、word vectorsをインポート
nlp = spacy.load('en_core_web_sm')

テキストのインポートとトークン化

# サンプルテキストに対する固有表現とエンティティタイプの抽出
text = u'My name is Ishio from Japan. Today, talk football!!'
doc = nlp(text)
token = doc[3] # Ishio
print([d for d in doc])
print(token)

出力結果。

[My, name, is, Ishio, from, Japan, ., Today, ,, love, football, !, !]
Ishio

品詞タグ付け

text = u'My name is Ishio from Japan. Today, talk football!!'
doc = nlp(text)
for d in doc:
    print((d.text, d.pos_, d.dep_))

出力結果。固有名詞はPROPNとなっています。

('My', 'ADJ', 'poss')
('name', 'NOUN', 'nsubj')
('is', 'VERB', 'ROOT')
('Ishio', 'PROPN', 'attr')
('from', 'ADP', 'prep')
('Japan', 'PROPN', 'pobj')
('.', 'PUNCT', 'punct')
('Today', 'NOUN', 'npadvmod')
(',', 'PUNCT', 'punct')
('love', 'NOUN', 'ROOT')
('football', 'NOUN', 'dobj')
('!', 'PUNCT', 'punct')
('!', 'PUNCT', 'punct')

固有表現抽出

spaCyの学習済みモデルを利用して、文章内から、固有表現を抽出します

print([(d.text, d.label_, spacy.explain(d.label_)) for d in doc.ents])

出力結果。

[('Ishio', 'ORG', 'Companies, agencies, institutions, etc.'),
 ('Japan', 'GPE', 'Countries, cities, states'),
 ('Today', 'DATE', 'Absolute or relative dates or periods')]

3つの単語が固有表現とそのエンティティタイプが抽出されました。ちなみに、spacy.explain()は、ラベルに対する説明を返してくれます。例えばORGは「Companies, agencies, institutions, etc.」という意味になります。Todayも固有名詞として認識されているが、DATEとして認識されています。IshioPERSONとして抽出されてほしかったですが、ORG(企業、組織等)として認識されました。(My Name is…としているのに。。。)。試しに、Ishioの部分をJohnに変更してみた結果、PERSONとして認識されました。

tokenに対する様々なメソッド

様々なNLPのためのメソッドが用意されていますので、いくつか試してみます。

text = u'My name is Ishio from Japan. I was born in Saitama!!'
token = doc[3] # Ishio
# トークン出力。
print(token)  # Ishio 
# 再掲:品詞
print(token.pos_)  # PROPN 
# 再掲:より細かめの品詞
print(token.tag_)  # PROPN 
# 言語
print(token.lang_)  # en 
# テキストの出力。末尾に空白文字があれば一緒に出力。
print(token.text_with_ws) # 'Ishio '
# 末尾に空白文字があれば出力。
print(token.whitespace_)
# エンティティのタイプ
print(token.ent_type_) # 'ORG'
# 小文字化
print(token.lower_) # ishio
# 接頭辞(デフォルト1文字)、接尾辞(デフォルト3文字)
print(token.prefix_, token.suffix_ ) #('I', 'hio')

token = doc[9] # born
# 見出し語(lemma)
print(token.lemma_) # bear
# 正規化(normalization)
print(token.norm_) # born

booleanを返してくれるメソッドも多数用意されています。多用しそうなものを列挙します

メソッド 意味
is_alpha  アルファベット
is_ascii  ASCII文字
is_digit  数字列
is_lower  小文字
is_upper  大文字
is_title  先頭大文字
is_punct  記号
is_left_punct  左に記号があるか。# e.g. (?
is_right_punct 左に記号があるか。# e.g. ]?
is_space 空白文字
is_quote クエスチョンマーク
is_currency 通貨記号
like_url URLっぽいtokenを判定
like_num 数字っぽいtokenを判定
like_email メールアドレスっぽいtokenを判定
is_stop ストップリストに含まれるか判定

「文」に分割

センテンス(文)に分割します。

text = (u"I am in Tokyo. I was born in Saitama.")
doc = nlp(text)
sents = list(doc.sents)
print(sents)

出力結果。

[I am in Tokyo., I was born in Saitama.]

Semantic Similarity(意味的類似性)

apples, _, oranges = nlp(u'apples and oranges')
a_o_similarity = apples.similarity(oranges)
o_a_similarity = oranges.similarity(apples)
print(a_o_similarity, o_a_similarity)

出力結果。0-1の値を返します。

0.60679483 0.60679483

text間の類似性も計算可能です。

doc1 = nlp(u"my name is John")
doc2 = nlp(u"my name is Ishio")
similarity = doc1.similarity(doc2)
print(similarity)

出力結果

0.9182574986865027

SpaCyとNLTKの比較

f:id:ishitonton:20181123150621p:plain

Processing pipelineの部分はまた今度勉強します。