1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

言語処理100本ノック-41:係り受け解析結果の読み込み(文節・係り受け)

Posted at

言語処理100本ノック 2015「第5章: 係り受け解析」41本目「係り受け解析結果の読み込み(文節・係り受け)」記録です。
前回は準備運動の内容だったので、今回からが係り受けの本番です。第5章は全体的に、第4章「形態素解析」のようにパッケージを活用した短いコード、というわけにはいかず、アルゴリズムを作っていかないといけません。今回はそんなに複雑ではないですが、それでもある程度考えさせられます。

参考リンク

リンク 備考
041.係り受け解析結果の読み込み(文節・係り受け).ipynb 回答プログラムのGitHubリンク
素人の言語処理100本ノック:41 多くのソース部分のコピペ元
CaboCha公式 最初に見ておくCaboChaのページ

環境

CRF++とCaboChaはインストールしたのが昔すぎてインストール方法忘れました。全然更新されていないパッケージなので、環境再構築もしていません。CaboChaをWindowsで使おうと思い、挫折した記憶だけはあります。確か64bitのWindowsで使えなかった気がします(記憶が曖昧だし私の技術力の問題も多分にあるかも)。

種類 バージョン 内容
OS Ubuntu18.04.01 LTS 仮想で動かしています
pyenv 1.2.16 複数Python環境を使うことがあるのでpyenv使っています
Python 3.8.1 pyenv上でpython3.8.1を使っています
パッケージはvenvを使って管理しています
Mecab 0.996-5 apt-getでインストール
CRF++ 0.58 昔すぎてインストール方法忘れました(多分make install)
CaboCha 0.69 昔すぎてインストール方法忘れました(多分make install)

第5章: 係り受け解析

学習内容

『吾輩は猫である』に係り受け解析器CaboChaを適用し,係り受け木の操作と統語的な分析を体験します.

クラス, 係り受け解析, CaboCha, 文節, 係り受け, 格, 機能動詞構文, 係り受けパス, Graphviz

ノック内容

夏目漱石の小説『吾輩は猫である』の文章(neko.txt)をCaboChaを使って係り受け解析し,その結果をneko.txt.cabochaというファイルに保存せよ.このファイルを用いて,以下の問に対応するプログラムを実装せよ.

41. 係り受け解析結果の読み込み(文節・係り受け)

40に加えて,文節を表すクラスChunkを実装せよ.このクラスは形態素(Morphオブジェクト)のリスト(morphs),係り先文節インデックス番号(dst),係り元文節インデックス番号のリスト(srcs)をメンバ変数に持つこととする.さらに,入力テキストのCaboChaの解析結果を読み込み,1文をChunkオブジェクトのリストとして表現し,8文目の文節の文字列と係り先を表示せよ.第5章の残りの問題では,ここで作ったプログラムを活用せよ.

回答

回答プログラム 041.係り受け解析結果の読み込み(文節・係り受け).ipynb

import re

# 区切り文字
separator = re.compile('\t|,')

# 係り受け
dependancy = re.compile(r'''(?:\*\s\d+\s) # キャプチャ対象外
                            (-?\d+)       # 数字(係り先)
                          ''', re.VERBOSE)

class Morph:
    def __init__(self, line):
        
        #タブとカンマで分割
        cols = separator.split(line)
        
        self.surface = cols[0] # 表層形(surface)
        self.base = cols[7]    # 基本形(base)
        self.pos = cols[1]     # 品詞(pos)
        self.pos1 = cols[2]    # 品詞細分類1(pos1)

class Chunk:
    def __init__(self, morphs, dst):
        self.morphs = morphs
        self.srcs = []   # 係り元文節インデックス番号のリスト
        self.dst  = dst  # 係り先文節インデックス番号
        self.phrase = ''.join([morph.surface for morph in morphs]) # 文節

# 係り元を代入し、Chunkリストを文のリストを追加
def append_sentence(chunks, sentences):
    
    # 係り元を代入
    for i, chunk in enumerate(chunks):
        if chunk.dst != -1:
            chunks[chunk.dst].srcs.append(i)
    sentences.append(chunks)
    return sentences, []

morphs = []
chunks = []
sentences = []

with open('./neko.txt.cabocha') as f:
    
    for line in f:
        dependancies = dependancy.match(line)
        
        # EOSまたは係り受け解析結果でない場合
        if not (line == 'EOS\n' or dependancies):
            morphs.append(Morph(line))
            
        # EOSまたは係り受け解析結果で、形態素解析結果がある場合
        elif len(morphs) > 0:
            chunks.append(Chunk(morphs, dst))
            morphs = []
       
        # 係り受け結果の場合
        if dependancies:
            dst = int(dependancies.group(1))
        
        # EOSで係り受け結果がある場合
        if line == 'EOS\n' and len(chunks) > 0:
            sentences, chunks = append_sentence(chunks, sentences)

for i, chunk in enumerate(sentences[7]):
    print('{}: {}, 係り先:{}, 係り元:{}'.format(i, chunk.phrase, chunk.dst, chunk.srcs))

回答解説

係り先取得の正規表現

係り先を取得できる正規表現を使っています。(-?\d+)が係り先の数字を取得する部分です。正規表現に関しては記事「ゼロから覚えるPython正規表現の基本とTips」を参照ください。
正規表現を使わなくても取得できると思いますが、練習のために使っています。

# 係り受け
dependancy = re.compile(r'''(?:\*\s\d+\s) # キャプチャ対象外
                            (-?\d+)       # 数字(係り先)
                          ''', re.VERBOSE)

Chunkクラス

ノックの指定にかかれていないphraseという変数も定義しています。後で出力するときに便利なので。srcsは定義だけしておき__init__では値の代入をしていません。

class Chunk:
    def __init__(self, morphs, dst):
        self.morphs = morphs
        self.srcs = []   # 係り元文節インデックス番号のリスト
        self.dst  = dst  # 係り先文節インデックス番号
        self.phrase = ''.join([morph.surface for morph in morphs]) # 文節

出力結果(実行結果)

プログラム実行すると以下の結果が出力されます。

出力結果
0: この, 係り先:1, 係り元:[]
1: 書生というのは, 係り先:7, 係り元:[0]
2: 時々, 係り先:4, 係り元:[]
3: 我々を, 係り先:4, 係り元:[]
4: 捕えて, 係り先:5, 係り元:[2, 3]
5: 煮て, 係り先:6, 係り元:[4]
6: 食うという, 係り先:7, 係り元:[5]
7: 話である。, 係り先:-1, 係り元:[1, 6]
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?