spaCyとGiNZAで名詞を抽出する【自然言語処理, Python】
目次
- spaCyとGiNZAで名詞を抽出する
- spaCyとは?
- GiNZAとは?
- spaCyとGiNZAのインストール
- spaCyの使い方を調べる
- spaCyで名詞を抽出する
- spaCyで名詞、代名詞、固有名詞を抽出する
- spaCyで名詞句を抽出する
- おわりに
spaCyとGiNZAで名詞を抽出する
私たちの話す言葉は「自然言語」と言いますが、これを計算機に処理させることを「自然言語処理」と言います。
自然言語処理を行うライブラリは沢山ありますが、今回はその中でもPythonのライブラリであるspaCyを使って見たいと思います。
今回はspaCyを使って日本語の文章から名詞を取り出してみます。
具体的にはspaCyについて↓を見ていきたいと思います。
spaCyとは?
GiNZAとは?
spaCyとGiNZAのインストール
spaCyの使い方を調べる
spaCyで名詞を抽出する
spaCyで名詞、代名詞、固有名詞を抽出する
spaCyで名詞句を抽出する
spaCyとは?
spaCy(スパイシー)とは自然言語処理を行うライブラリです。
PythonとCythonで書かれており、Pythonから使うことができます。
オープンソースのソフトウェアで、MITライセンスで公開されており、商用利用も可能です。
また英語、ドイツ語、スペイン語などといった色々な言語において学習済み統計モデルと単語ベクトルを利用することができます。
プロダクトの製品化を意識した開発がされているのが特徴です。
spaCyを使えば日本語の文章を解析して単語ごとに分割したり(字句解析)、単語間の依存関係を見たり(構文解析)することが可能になるということです。
つまりspaCyを使えば機械学習に使用するデータを簡単に用意出来たり、あるいは自然言語処理として文章を解析することが出来るようになるということになります。
Pythonから利用するにはpipでインストールすればすぐに使うことができます。
インストール方法については後述します。
GiNZAとは?
spaCyは内部的には学習済み統計モデルを使って解析を行います。
最近までこの学習済みモデルに日本語のモデルが無い状態でした。
つまりspaCyで日本語の文章について深い解析が出来ない状態が続いていました。
しかし、GiNZAの登場によってspaCyの日本語対応は大きく変わりました。
GiNZAはリクルートと国立国語研究所が開発したライブラリで字句解析や構文解析を行えます。
つまりspaCyからGiNZAのモデルをロードすることでGiNZAを使った日本語の解析ができるということになります。
GiNZAはオープンソースなライブラリで、MITライセンスで利用することが可能です。
- GiNZA - Japanese NLP Library | Universal Dependenciesに基づくオープンソース日本語NLPライブラリ
- megagonlabs/ginza: A Japanese NLP Library using spaCy as framework based on Universal Dependencies
- はじめての自然言語処理 spaCy/GiNZA を用いた自然言語処理 | オブジェクトの広場
spaCyとGiNZAのインストール
spaCyとGiNZAはともにPythonのライブラリで、pipを使えばすぐにインストールすることができます。
GiNZAをインストールするには↓のコマンドを実行します。
$ pip install "https://github.com/megagonlabs/ginza/releases/download/latest/ginza-latest.tar.gz"
spaCyをインストールするには↓のコマンドを実行します。
$ pip install spacy
GiNZAのバージョンによってはspaCyの実行時に警告が出ることがあります。
例えば↓のような警告です。
UserWarning: [W031] Model 'ja_ginza' (2.2.0) requires spaCy v2.2 and is incompatible with the current spaCy version (2.3.5). This may lead to unexpected results or runtime errors. To resolve this, download a newer compatible model or retrain your custom model with the current spaCy version. For more details and available updates, run: python -m spacy validate warnings.warn(warn_msg)
↑のようにバージョンによる警告が出た場合はspaCyのインストールバージョンを指定します。
↑の場合はインストールしたGiNZA(2.2.0)がspaCy(2.3.5)に対応しておらず、spaCy(2.2)にしてくれと言ってるので↓のようにします。
$ pip uninstall spacy $ pip install spacy==2.2
spaCyの使い方を調べる
spaCyのAPIのドキュメントは↓を参照します。
Doc
やToken
の属性の説明などについては↑から調べればわかります。英語なので機械翻訳を活用しましょう。
(^ _ ^) | 自然言語だけに |
spaCyで名詞を抽出する
それではspaCyで実際に日本語の文章から名詞を抽出してみたいと思います。
spaCyはお決まりとして最初にspacy
をインポートして、モデルをロードしておく必要があります。
今回はロードするモデルはGiNZAのモデルです。
↓のようにします。
import spacy nlp = spacy.load('ja_ginza') # モデルのロード
load()
の結果は慣例としてnlp
という変数で受け取っておきます。
このnlp
を操作することで自然言語処理を行えます。
ja_ginza
をロードした場合はこのnlp
はginza.Japanese
クラスになります。
日本語の文章を解析させるには↓のようにnlp()
に文章を渡します。
doc = nlp('アマゾンの奥地で彼は毒キノコを取った。') # 解析を行う
nlp()
に文章を渡すと解析が行われ、その結果が返り値として返ってきます。
この返り値は慣例的にdoc
とするのが一般的みたいです。
このdoc
はspacy.tokens.doc.Doc
クラスです。
doc
はfor
文で回すとトークン列のジェネレーターを生成してくれます。
したがってdoc
をfor
文で回すと↓のようにトークンを取り出すことができます。
import spacy nlp = spacy.load('ja_ginza') doc = nlp('アマゾンの奥地で彼は毒キノコを取った。') for tok in doc: print( tok.i, # 親ドキュメント内のトークンのインデックス。 tok.text, # 逐語的なテキストコンテンツ # 逐語的なテキストコンテンツ(Token.textと同じ) # 主に他の属性との一貫性のために存在します。 tok.orth_, tok.lemma_, # 語尾変化のない接尾辞のない、トークンの基本形式 tok.pos_, # 品詞(英語の大文字) tok.tag_, # きめの細かい品詞 tok.head.i, # headはこのトークンの構文上の親、または「ガバナー」 tok.dep_, # 構文従属関係 # トークンの基準、つまりトークンテキストの正規化された形式 # 通常、言語のトークナイザー例外またはノルム例外で設定されます。 tok.norm_, # 名前付きエンティティタグのIOBコード # 「B」はトークンがエンティティを開始することを意味し、「I」はそれがエンティティの内部にあることを意味し、 # 「O」はそれがエンティティの外部にあることを意味し、「」はエンティティタグが設定されていないことを意味します。 tok.ent_iob_, tok.ent_type_, # 名前付きエンティティタイプ )
doc
はfor
文で回すとspacy.tokens.token.Token
を返してくれます。
このToken
には↑のようにさまざまな属性があり、それらの属性を参照することでその単語が持つ情報を参照することができます。
つまり今回はこのトークンの属性を参照して名詞を抽出してみようという話です。
tok.text
などの「逐語的なテキストコンテンツ」というのはなんか難しい表現ですが、要は表層形のことだと思われます。
表層形とは元の文章のそのままの表記の文字列のことです。
↑のコードを実行すると↓のような結果になります。
0 アマゾン アマゾン アマゾン PROPN 名詞-固有名詞-地名-一般 2 nmod アマゾン B LOC 1 の の の ADP 助詞-格助詞 0 case の O 2 奥地 奥地 奥地 NOUN 名詞-普通名詞-一般 9 nmod 奥地 O 3 で で で ADP 助詞-格助詞 2 case で O 4 彼 彼 彼 PRON 代名詞 9 nsubj 彼 O 5 は は は ADP 助詞-係助詞 4 case は O 6 毒 毒 毒 NOUN 名詞-普通名詞-一般 7 compound 毒 O 7 キノコ キノコ 茸 NOUN 名詞-普通名詞-一般 9 obj キノコ O 8 を を を ADP 助詞-格助詞 7 case を O 9 取っ 取っ 取る VERB 動詞-一般 9 ROOT 取っ O 10 た た た AUX 助動詞 9 aux た O 11 。 。 。 PUNCT 補助記号-句点 9 punct 。 O
↑のうち、tok.pos_
を参照して得られるPROPN
やADP
, NOUN
などがそのトークンの品詞を表しています。
品詞を参照することでそのトークンが名詞かどうか判別することができます。
「名詞」の場合、NOUN
というのがそれに当たります。
つまりtok.pos_
の値がNOUN
のトークンを保存しておけば名詞のトークンを抽出できるということになります。
↓のようにです。
import spacy nlp = spacy.load('ja_ginza') # モデルのロード doc = nlp('アマゾンの奥地で彼は毒キノコを取った。') # 文章の解析 # NOUN(名詞)のトークンを抽出 noun_toks = [] for tok in doc: if tok.pos_ == 'NOUN': noun_toks.append(tok) # 抽出したトークン列を表示する for tok in noun_toks: print(tok.text)
↑のコードを実行すると↓のような結果になります。
奥地 毒 キノコ
tok.pos_
のNOUN
やPROPN
の意味を調べるには以前は↓のドキュメントが有効でした。
しかし現在はドキュメントの仕様が変わったみたいで、参照できなくなっています。
第3者の人が作成したQiitaのドキュメントがありますのでこちらを参照してみてください。
spaCyで名詞、代名詞、固有名詞を抽出する
さきほどの名詞を抽出した要領で今度は名詞、代名詞、固有名詞のトークンを抽出してみたいと思います。
名詞はpos_
の値ではNOUN
で、代名詞はPRON
, そして固有名詞はPROPN
です。
NOUN ... 名詞
PRON ... 代名詞
PROPN ... 固有名詞
これらのトークンを抽出するコードを書くと↓のようになります。
import spacy nlp = spacy.load('ja_ginza') # モデルのロード doc = nlp('アマゾンの奥地で彼は毒キノコを取った。') # 文章の解析 # 名詞、代名詞、固有名詞のトークンを抽出 noun_toks = [] for tok in doc: if tok.pos_ in ('NOUN', 'PRON', 'PROPN'): noun_toks.append(tok) # 抽出したトークン列を出力 for tok in noun_toks: print(tok.text, tok.pos_)
↑のコードを実行すると↓のような結果になります。
アマゾン PROPN 奥地 NOUN 彼 PRON 毒 NOUN キノコ NOUN
spaCyで名詞句を抽出する
spaCyでは名詞句を抽出することができます。
名詞句を抽出するにはdoc.noun_chunks
を参照します。
import spacy nlp = spacy.load('ja_ginza') # モデルのロード doc = nlp('アマゾンの奥地で彼は毒キノコを取った。') # 文章の解析 # 名詞句を抽出 for span in doc.noun_chunks: print(span)
↑のコードを実行すると↓のような結果になります。
アマゾン 奥地 彼 毒キノコ
「毒キノコ」が「毒」と「キノコ」にわけられずに1つの名詞句として取得できてるのがわかります。
ちなみにnoun_chunks
が生成するオブジェクトはspacy.tokens.span.Span
です。
おわりに
今回はspaCyとGiNZAを使って日本語の文章から名詞を抽出してみました。
spaCyとGiNZAを使えば簡単に日本語の文章を解析できそうです。
(^ _ ^) | 簡単と言っても意味解析以上のことはけっこうしんどそう |
(・ v ・) | それはどこでもいっしょ |
(^ _ ^) | NLPウォリアーに栄光あれ |