yasuokaの日記: 『言語処理100本ノック 2020』「48. 名詞から根へのパスの抽出」をGiNZAで解いてみる
昨日の日記で指摘した『言語処理100本ノック 2020』の「48. 名詞から根へのパスの抽出」を、GiNZAで解いてみることにした。まずは問題文。
48. 名詞から根へのパスの抽出
文中のすべての名詞を含む文節に対し,その文節から構文木の根に至るパスを抽出せよ. ただし,構文木上のパスは以下の仕様を満たすものとする.
- 各文節は(表層形の)形態素列で表現する
- パスの開始文節から終了文節に至るまで,各文節の表現を” -> “で連結する
「吾輩はここで始めて人間というものを見た」という文(neko.txt.cabochaの8文目)から,次のような出力が得られるはずである.
吾輩は -> 見た
ここで -> 始めて -> 人間という -> ものを -> 見た
人間という -> ものを -> 見た
ものを -> 見た
この問題に対し、私(安岡孝一)なりに知恵を絞って、Google Colaboratory上で解いてみた。ただし、クラスMorph・Chunkの代わりに、それぞれToken・Spanを拡張する形にした。
!pip install ginza
from spacy.tokens import Token,Span,Doc
Token.set_extension("surface",getter=lambda token:token.orth_,force=True)
Token.set_extension("base",getter=lambda token:token.lemma_,force=True)
Token.set_extension("pos",getter=lambda token:token.pos_,force=True)
Token.set_extension("pos1",getter=lambda token:token.tag_,force=True)
Span.set_extension("morphs",getter=lambda span:span,force=True)
Span.set_extension("dst",getter=lambda span:max(t.head._.bunsetu_index for t in span),force=True)
Span.set_extension("srcs",getter=lambda span:{s[0]._.bunsetu_index for s in span.doc._.chunks if s._.dst==span[0]._.bunsetu_index},force=True)
def _make_chunks(doc):
b=[i for i,t in enumerate(doc) if t._.bunsetu_bi_label=="B"]
return [Span(doc,s,e) for s,e in zip(b,b[1:]+[len(doc)])]
Doc.set_extension("chunks",getter=_make_chunks,force=True)
import ja_ginza
nlp=ja_ginza.load()
doc=nlp("吾輩はここで始めて人間というものを見た")
chunks=doc._.chunks
for c in chunks:
if [t for t in c._.morphs if t._.pos in {"NOUN","PRON","PROPN"}]!=[]:
s=str(c)
d=chunks[c._.dst]
while d!=c:
s+=" -> "+str(d)
c=d
d=chunks[c._.dst]
print(s)
この結果、私の手元では、以下の出力が得られた。
吾輩は -> 見た
ここで -> 始めて -> 見た
人間という -> ものを -> 見た
ものを -> 見た
プログラム自体は、間違ってないはずなんだけどなぁ。困ったなぁ。
『言語処理100本ノック 2020』「48. 名詞から根へのパスの抽出」をGiNZAで解いてみる More ログイン