自然言語処理関連のソフトを作る機会があり、最近のメジャーな日本語自然言語処理ライブラリとしてGiNZAというものがあるという話を聞いたので試しに使ってみました。
GiNZAとは
GiNZAとはリクルートが国立国語研究所との共同研究成果をもとに開発した日本語自然言語処理ライブ来です。
形態素解析器であるSudachiPyと機械学習部分であるspaCyを合わせたライブラリのようです。
特徴は従来のspaCyは日本語に対してはMeCabをバックエンドに形態素解析ができる程度でした。
しかし。GiNZAの登場により最先端の機械学習技術を用いた日本語自然言語処理が簡単にできるようになったようです。
GiNZAのインストール
今回は2021年9月現在GiNZAの最新バージョンであるGiNZA v5.0をインストールしていきます。
GiNZA v5はインストール時に解析モデルのパッケージを指定する必要があるようで、解析度重視の場合は以下のコマンドでインストールしましょう。
pip install -U ginza ja-ginza-electra
速度重視の場合は以下のコマンドでインストールしてください。
pip install -U ginza ja-ginza
両方使い分けたい場合は、両コマンドとも実行してください。
インストールができたら動作を確認してみましょう。
ginzaすもももももももものうち。
# text = すもももももももものうち。1 すもも すもも NOUN 名詞-普通名詞-一般 _ 3 nsubj _ SpaceAfter=No|BunsetuBILabel=B|BunsetuPositionType=SEM_HEAD|NP_B|Reading=スモモ|NE=B-OTHERS|ENE=B-Flora2 も も ADP 助詞-係助詞 _ 1 case _ SpaceAfter=No|BunsetuBILabel=I|BunsetuPositionType=SYN_HEAD|Reading=モ3 もも もも NOUN 名詞-普通名詞-一般 _ 5 nsubj _ SpaceAfter=No|BunsetuBILabel=B|BunsetuPositionType=SEM_HEAD|NP_B|Reading=モモ|NE=B-OTHERS|ENE=B-Animal_Part4 も も ADP 助詞-係助詞 _ 3 case _ SpaceAfter=No|BunsetuBILabel=I|BunsetuPositionType=SYN_HEAD|Reading=モ5 もも もも NOUN 名詞-普通名詞-一般 _ 7 nmod _ SpaceAfter=No|BunsetuBILabel=B|BunsetuPositionType=SEM_HEAD|NP_B|Reading=モモ|NE=B-OTHERS|ENE=B-Color_Other6 の の ADP 助詞-格助詞 _ 5 case _ SpaceAfter=No|BunsetuBILabel=I|BunsetuPositionType=SYN_HEAD|Reading=ノ7 うち うち NOUN 名詞-普通名詞-副詞可能 _ 0 root _ SpaceAfter=No|BunsetuBILabel=B|BunsetuPositionType=ROOT|NP_B|Reading=ウチ8 。 。 PUNCT 補助記号-句点 _ 7 punct _ SpaceAfter=No|BunsetuBILabel=I|BunsetuPositionType=CONT|Reading=。
PythonでGiNZAを操作する
インストールができたろころでPythonでGiNZAを操作していきましょう。
1.文境界解析
文境界解析は文章から文の境界を検出する処理です。
import spacy
nlp = spacy.load('ja_ginza_electra')doc = nlp('銀座でランチをご一緒しましょう今度の日曜日はどうですか。')
# 文境界解析for sent in doc.sents: print(sent)
銀座でランチをご一緒しましょう今度の日曜日はどうですか。
"。"がなくても文の境界が判断できていますね。
2.形態素解析
形態素解析は文章を単語に分割すると同時に単語の品詞などを推測する処理です。
import spacy
nlp = spacy.load('ja_ginza_electra')doc = nlp('銀座でランチをご一緒しましょう。')for sent in doc.sents: for token in sent: print(token.i, token.orth_, token.lemma_, token.pos_, token.tag_, token.dep_, token.head.i) print('EOS')
0 銀座 銀座 PROPN 名詞-固有名詞-地名-一般 obl 51 で で ADP 助詞-格助詞 case 02 ランチ ランチ NOUN 名詞-普通名詞-一般 obj 53 を を ADP 助詞-格助詞 case 24 ご ご NOUN 接頭辞 compound 55 一緒 一緒 VERB 名詞-普通名詞-サ変可能 ROOT 56 し する AUX 動詞-非自立可能 aux 57 ましょう ます AUX 助動詞 aux 58 。 。 PUNCT 補助記号-句点 punct 5EOS
3.係り受け解析
係り受け解析は単語間の関係を解析する処理です。
以下のサンプルは係り受け木をSVG形式で保存しています。
# -*- coding: utf-8 -*-# 文境界解析
import spacyfrom spacy import displacyfrom pathlib import Path
nlp = spacy.load('ja_ginza_electra')doc = nlp("銀座でランチをご一緒しましょう。")for sent in doc.sents: svg = displacy.render(sent, style="dep") file_name = "kakari.svg" output_path = Path("./" + file_name) output_path.open("w", encoding="utf-8").write(svg)
4.固有表現抽出
固有表現抽出は国名、人名などの固有表現を抽出する処理です。
import spacyfrom spacy import displacy
nlp = spacy.load('ja_ginza_electra')doc = nlp("山田さんと銀座でランチをご一緒しましょう。")for ent in doc.ents: print( ent.text+','+ # テキスト ent.label_+','+ # ラベル str(ent.start_char)+','+ # 開始位置 str(ent.end_char)) # 終了位置
山田,Person,0,2さん,Title_Other,2,4銀座,City,5,7
5.単語の分散表現
GiNZAでは学習済みの単語分散表現(word2vec)も使用できるみたいです。
分散表現は300次元ですが今回は最初の2次元だけ表示します。分散表現が学習されていない単語はALL 0になるみたいですね。
また、L2ノルムも取得することができます。
分散表現はja_ginza_electraでは学習済みモデルがないみたいなので、ja_ginzaを使用しています。
import spacy
nlp = spacy.load('ja_ginza') doc = nlp("銀座でランチをご一緒しましょう。")for token in doc: print(token.text, token.vector[:2], token.has_vector, token.vector_norm)
銀座 [ 0.55935055 -0.02516028] True 3.8992517で [-0.09195102 -0.10327693] True 1.8796002ランチ [ 0.23565347 -0.08456942] True 3.8218849を [-0.19509408 -0.13202968] True 2.0958433ご [0.33537257 0.21526141] True 2.8017106一緒 [-0.1381576 -0.10699644] True 2.5291438し [ 0.00739705 -0.32393304] True 2.2611105ましょう [0. 0.] False 0.0。 [ 0.12551211 -0.1708449 ] True 2.4466825
また、以下のように書くことで文のベクトル表現なども簡単に表現できます(各単語のベクトルを足して平均を求めている)。
import spacy
nlp = spacy.load('ja_ginza') doc = nlp("銀座でランチをご一緒しましょう。")print(doc.vector[:2])
[ 0.09312034 -0.08128325]
まとめ
GiNZAの基本的な処理について一通り触れてみましたが正直むちゃくちゃ便利です。
spaCyに関する知識が少ないのでGiNZAを有効活用できるようにそのあたりも勉強していこうと思います。