GiNZA入門 (2) - 固有表現抽出
「GiNZA」の固有表現抽出の使い方をまとめました。
・GiNZA 4.0.5
前回
1. GiNZA のインストール
(1) 「Google Colab」で以下のコマンドを実行。
!pip install -U ginza
(2) メニュー「ランタイム → ランタイムを再起動」で「Google Colab」を再起動。
2. 固有表現抽出の実行
「固有抽出表現」は、文章から人名や場所名などの「固有表現」(名前付きエンティティ)を抽出する処理です。
import spacy
# GiNZAの準備
nlp = spacy.load('ja_ginza')
# 固有表現抽出の実行
doc = nlp('夏目金之助(後の漱石)は、1867年2月9日に江戸の牛込馬場下にて、名主の夏目小兵衛直克・千枝夫妻の末子として出生した。')
for ent in doc.ents:
print(
ent.text+','+ # テキスト
ent.label_+','+ # ラベル
str(ent.start_char)+','+ # 開始位置
str(ent.end_char) # 終了位置
)
夏目金之助,Person,0,5
漱石,Person,8,10
1867年2月9日,Date,13,22
江戸,City,23,25
牛込馬場下,City,26,31
夏目小兵衛,Person,37,42
千枝,Person,45,47
「エンティティ」のプロパティは、次のとおりです。
・text : テキスト。
・ent.label_ : ラベル。
・ent.start_char : 開始位置。
・ent.end_char : 終了位置。
ラベルは、次のとおりです。
3. 固有表現抽出のルールの追加
文章によっては、抽出できていない固有表現もあります。
import spacy
# GiNZAの準備
nlp = spacy.load('ja_ginza')
# 固有表現抽出の実行
doc = nlp('小学生のサツキと妹のメイは、母の療養のために父と一緒に初夏の頃の農村へ引っ越してくる。')
for ent in doc.ents:
print(
ent.text+','+ # テキスト
ent.label_+','+ # ラベル
str(ent.start_char)+','+ # 開始位置
str(ent.end_char) # 終了位置
)
小学生,School_Age,0,3
初夏,Date,27,29
抽出できていない固有表現は、以下のようにルールで追加することができます。
import spacy
# GiNZAの準備
nlp = spacy.load('ja_ginza')
# ルールの追加
from spacy.pipeline import EntityRuler
ruler = EntityRuler(nlp)
ruler.add_patterns([
{"label": "Person", "pattern": "サツキ"},
{"label": "Person", "pattern": "メイ"}])
nlp.add_pipe(ruler)
# 固有表現抽出の実行
doc = nlp('小学生のサツキと妹のメイは、母の療養のために父と一緒に初夏の頃の農村へ引っ越してくる。')
for ent in doc.ents:
print(
ent.text+','+ # テキスト
ent.label_+','+ # ラベル
str(ent.start_char)+','+ # 開始位置
str(ent.end_char) # 終了位置
)
小学生,School_Age,0,3
サツキ,Person,4,7
メイ,Person,10,12
初夏,Date,27,29
4. 固有表現抽出のモデルの学習
◎ 固有表現抽出のモデルの学習
固有表現抽出のモデルを自前の学習データで学習させることもできます。
import spacy
import random
# 固有抽出表現の学習
def train_ner(train_data, epoch):
# 日本語の空モデルの生成
nlp = spacy.blank('ja')
# 固有表現抽出のパイプの追加
if 'ner' not in nlp.pipe_names:
ner = nlp.create_pipe('ner')
nlp.add_pipe(ner, last=True)
# ラベルの追加
for _, annotations in train_data:
for ent in annotations.get('entities'):
ner.add_label(ent[2])
# 固有表現抽出のみ学習
other_pipes = [pipe for pipe in nlp.pipe_names if pipe != 'ner']
with nlp.disable_pipes(*other_pipes):
optimizer = nlp.begin_training()
# 学習ループ
for itn in range(epoch):
# シャッフル
random.shuffle(train_data)
# 学習
losses = {}
for text, annotations in train_data:
nlp.update([text], [annotations], drop=0.2, sgd=optimizer, losses=losses)
print('iteration'+str(itn)+': '+str(losses['ner']))
return nlp
# 学習データの準備
train_data = [
('サツキの通う学校が田植え休みの日、入院している母の見舞いに行った二人はオバケ屋敷のことを報告する。',
{'entities': [(0, 3, 'Person'),(24, 25, 'Person')]}),
('サツキとメイが森にあるバス停で雨の中父の帰りを待っていると、そこへ頭に葉っぱを乗せたトトロがやって来る。',
{'entities': [(0, 3, 'Person'), (4, 6, 'Person'), (18, 19, 'Person'), (42, 45, 'Person')]}),
('1人で遊んでいたメイは庭で不思議な生き物を見つける。',
{'entities': [(8, 10, 'Person')]}),
('人が住み始めるといつのまにか居なくなるという話を聞いてサツキは拍子抜けし、メイは「つまんない」とぼやく。',
{'entities': [(27, 30, 'Person'), (37, 39, 'Person')]})
]
# 固有表現抽出の学習
nlp = train_ner(train_data, 100)
# 固有表現抽出モデルの保存
nlp.to_disk('ner_model')
# 固有表現抽出の実行
doc = nlp('小学生のサツキと妹のメイは、母の療養のために父と一緒に初夏の頃の農村へ引っ越してくる。')
for ent in doc.ents:
print(
ent.text+','+ # テキスト
ent.label_+','+ # ラベル
str(ent.start_char)+','+ # 開始位置
str(ent.end_char) # 終了位置
)
サツキ,Person,4,7
メイ,Person,10,12
父,Person,22,23
学習した固有表現抽出モデルの実行方法は、次のとおりです。
import spacy
# 固有表現抽出モデルの読み込み
nlp = spacy.load('ner_model')
# 固有表現抽出の実行
doc = nlp('小学生のサツキと妹のメイは、母の療養のために父と一緒に初夏の頃の農村へ引っ越してくる。')
for ent in doc.ents:
print(
ent.text+','+ # テキスト
ent.label_+','+ # ラベル
str(ent.start_char)+','+ # 開始位置
str(ent.end_char) # 終了位置
)
サツキ,Person,4,7
メイ,Person,10,12
父,Person,22,23
◎ Wikipediaを用いた固有表現抽出データセットでの学習
ストックマークの「Wikipediaを用いた日本語の固有抽出表現データセット」で学習する手順は、次のとおりです。
(1) 固有抽出表現データセット(ner.json)のダウンロード。
(2) 「学習データの準備」の部分を以下のように書き換える。
# 学習データの準備
import json
labels = {
'人名': 'Person',
'法人名': 'Juridical_Person',
'政治的組織名': 'Political_Organization',
'その他の組織名': 'Organization_Other',
'地名': 'Location',
'施設名': 'Facility',
'製品名': 'Product',
'イベント名': 'Event',
}
json_data = json.load(open('ner.json', 'r'))
train_data = []
for data in json_data:
text = data['text']
entities = data['entities']
value = []
for entity in entities:
span = entity['span']
label = labels[entity['type']]
value.append((span[0], span[1], label))
train_data.append((text, {'entities': value}))
5. 参考
次回
この記事が気に入ったらサポートをしてみませんか?