🐍

GiNZAを利用して、主語・述語・目的語、修飾被修飾関係などを抽出する

2023/12/20に公開

環境

WSL 2
Python 3.10.12
pip 23.3.1

GiNZA インストール(コマンド)

以下でspacyも入ります。

pip install -U ginza

私の場合、spacy 3.6.1、ginza 5.1.3でした。

主語・述語を出す

以下のコードで、主語・述語を出すことができます。

引用したコード
import spacy
def parse_document(sentence, nlp):
    doc = nlp(sentence)
    tokens = []

    for sent in doc.sents:
        for token in sent:
            tokens.append(token)

    subject_list = []

   for token in tokens:
       ## 依存関係ラベルがnsubj=>「<見出し語>:<係り先の見出し語>」をリストに追加する。
       if token.dep_ in  ["nsubj", "iobj"]:
           subject_list.append(f"{token.lemma_}:{tokens[token.head.i].lemma_}")
   
   return subject_list
## ここからメイン
nlp = spacy.load('ja_ginza')
print(parse_document("昨日から胃がキリキリと痛い。ただ、熱は無い。", nlp))

Output

['胃:痛い', '熱:無い']

参考

https://zenn.dev/massan/articles/3c40a8951db395#主語と述語を抜き出す

修飾・被修飾関係を出す

以下のコードで、係り受け解析できます。

dep = DependencyAnalysis()

res = dep.analyze('チーム開発を通して生徒同士の交流を図っています。')


for r in res:
   print(f'{r[0]}{r[1]}')
引用したコード(DependencyAnalysis())
import spacy
import ginza
import codecs

class DependencyAnalysis:

   def __init__(self):
       """
       コンストラクタ
       """
       self.nlp = spacy.load("ja_ginza_electra")
       self.document = None

   def read_file(self,filename,encoding='utf-8'):
       '''
       ファイルの読み込み

       Parameters:
       --------
           filename : str   分析対象のファイル名 
       '''
       with codecs.open(filename,'r',encoding,'ignore') as f:
           self.read_text(f.read())

   def read_text(self,text):
       '''
       テキストの読み込み

       Parameters:
       --------
           text : str  分析対象のテキスト
       '''
       self.document = text

   def analyze(self,text = None,mode = 0):
       '''
       係り受け結果を主辞(文節で一番重要な単語)で出力

       Parameters:
       --------
           mode : int  0=通常の係り受け 1:係り受けされる側(左)のみに主辞を適用 2: 両方に主辞を適用  
       '''
       ret = []

       # mode が 1以下の場合、通常の係り受け関数、2の場合は主辞の関数を使用する
       func = ginza.bunsetu_spans if mode <= 1 else ginza.bunsetu_phrase_spans 
       
       # 引数があればそれを、Noneの場合はインスタンス変数の self.textを使う
       doc = self.nlp(self.document if text == None else text)
       
       # 文書から一文を取り出す
       for sentence in doc.sents:
           # 係り受けの関数を適用
           for span in func(sentence):
               # 係り受け解析結果を取り出す
               for token in span.lefts:
                   # modeが 1 の場合のみ、係り受け元を文節として取り出す。(例 mode=0 or 2:交流を mode=1:交流)
                   key = token if mode >= 1 else ginza.bunsetu_span(token) 
                   # 結果を辞書に登録
                   ret.append((str(key),str(span)))
       return ret

参考

https://resanaplaza.com/2022/09/11/【実践】pythonとginzaで係り受け解析しようか!/

目的語を出す

import spacy
from spacy.symbols import obj

nlp = spacy.load('ja_ginza')  # モデルをロード
doc = nlp('私は猫を撫でた')  # 文章を解析

for tok in doc:
   if tok.dep == obj:  # トークンが目的語なら
       print(tok.text)  # テキストを表示

Output

参考

https://yu-nix.com/archives/spacy-obj/#目的語とは?

まとめ

今回は、GiNZAを用いて、係り受け解析などをしたので、それを備忘録としてまとめました。
obj以外のパラメータについて、以下のノートに詳しく載っていたので、参考にどうぞ。
https://note.com/npaka/n/n5c3e4ca67956

Discussion