"Diary" インターネットさんへの恩返し

いつもソースコードコピペばかりなので,みなさまへ少しばかりの恩返しを

言語処理100本ノック 2015をやってみた(第5章 その1 40,41)



スポンサーリンク

www.cl.ecei.tohoku.ac.jp

5章難しくてなかなか進まない。プログラムが長くなってしまうので小出しで行きます。

5章で使うCabochaについて

CabochaというSupport Vector Machines に基づく日本語係り受け解析器ということで、このモジュールに文章をぶち込むと、文節に分解しさらに、どの文節番号にかかっているかとか出力してくれます。聞いたこともないツールなので、私みたいな初心者は一度、以下をざっと見たほうが理解が早いです。

  • Cabochaとは

CaoboCha: Yet Another Japanese Dependency Structure Analyzer

  • Cabochaのインストール方法

CabochaのUbuntuへのインストール(Pythonでテスト) - "Diary" インターネットさんへの恩返し

  • Cabochaの出力結果の解説。

http://qiita.com/nezuq/items/f481f07fc0576b38e81d

準備

「neko.txt.cabocha」への保存。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import CaboCha

c = CaboCha.Parser()
f_r = open('neko.txt','r')
f_w = open('neko.txt.cabocha','a')

line = f_r.readline() # 1行を文字列として読み込む(改行文字も含まれる)

while line:
        if len(line)>1: //行に一文字以上ある場合
                tree =  c.parse(line[:-1])
                f_w.write(tree.toString(CaboCha.FORMAT_LATTICE))
        line = f_r.readline()

f_r.close
f_w.close


「f_w.write(tree.toString(CaboCha.FORMAT_LATTICE))」で1文を分解して以下の様な形にして「neko.txt.cabocha」へ書込。

* 1 2D 0/1 -0.764521
吾輩    名詞,代名詞,一般,*,*,*,吾輩,ワガハイ,ワガハイ
は      助詞,係助詞,*,*,*,*,は,ハ,ワ
* 2 -1D 0/2 0.000000
猫      名詞,一般,*,*,*,*,猫,ネコ,ネコ
で      助動詞,*,*,*,特殊・ダ,連用形,だ,デ,デ
ある    助動詞,*,*,*,五段・ラ行アル,基本形,ある,アル,アル
。      記号,句点,*,*,*,*,。,。,。
EOS

上記リンクに説明がありますがそれぞれの行は以下の意味を持つ

[1行目]

* 文節番号 係り先の文節番号(係り先なし:-1) 主辞の形態素番号/機能語の形態素番号 係り関係のスコア(大きい方が係りやすい)

[2-3行目]

表層形 品詞 品詞細分類1 品詞細分類2 品詞細分類3 活用形 活用型 原形 読み 発音 

1-3行名で1文節。4-8で2文節目。「EOS」文章終わり。

40. 係り受け解析結果の読み込み(形態素

オブジェクトのイメージ
f:id:azumami:20151106115600p:plain

【プログラム】

# coding: utf-8
import sys
import re
import json

f = open('neko.txt.mecab','r')

class Morph:

    def __init__(self,surface,base,pos,pos1):
        self.surface =    surface
        self.base    =    base
        self.pos     =    pos
        self.pos1    =    pos1

if __name__ == "__main__":

        f = open('neko.txt.cabocha','r')

        tmp1 = []
        temp1 = {}
        no_sentence = 0
        no_word = 0
        temp1[no_sentence] = {}

        #2次元配列(行:文番号、列:単語番号)に形態素列クラスを入れる
        for i,line in enumerate(f):
                if "EOS" == line[0:3]:
                        no_sentence += 1
                        no_word = 0
                        temp1[no_sentence] = {}
                        #print "\n\n"

                #空白を除去したい
                if ("*" != line[0:1]) and ("EOS" != line[0:3]):

                        # \tか,でスプリット
                        tmp1 = filter(lambda w: len(w) > 0, re.split(r'\t|,', line))

                        if tmp1[2]!="空白":
                                #0:表層形,1:品詞,2:品詞細分類1,3:品詞細分類2,4:品詞細分類3,5:活用形,6:活用型,7:原形,8:読み,9:発音
                                #print line[:-1] + " => " + str(no_sentence) + "文目の " + str(no_word) + " 文字目"


                                #2次元配列に形態素列インスタンス格納
                                temp1[no_sentence][no_word] = Morph(tmp1[0],tmp1[7],tmp1[1],tmp1[2])
                                no_word += 1

        #3文目の形態素列
        for a in temp1[2]:
                print "表層形:" + temp1[2][a].surface + "\t原形:" + temp1[2][a].base  + "\t品詞:" + temp1[2][a].pos  + "\t品詞細分類1:" + temp1[2][a].pos1

【実行結果】

$ sudo python 40.py
表層形:名前     原形:名前       品詞:名詞       品詞細分類1:一般
表層形:は       原形:は 品詞:助詞       品詞細分類1:係助詞
表層形:まだ     原形:まだ       品詞:副詞       品詞細分類1:助詞類接続
表層形:無い     原形:無い       品詞:形容詞     品詞細分類1:自立
表層形:。       原形:。 品詞:記号       品詞細分類1:句点

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

オブジェクトのイメージ
f:id:azumami:20151109121605p:plain

【プログラム】

#coding: utf-8
import sys
import re
import json

f = open('neko.txt.mecab','r')

class Morph:
        def __init__(self,surface,base,pos,pos1):
                self.surface =    surface
                self.base    =    base
                self.pos     =    pos
                self.pos1    =    pos1

class Chunk:
        def __init__(self):
                self.morphs = []
                self.dst    = 0
                self.srcs   = []


if __name__ == "__main__":

        f = open('neko.txt.cabocha','r')
        tmp1 = []
        tmp2 = []
        temp1 = {}
        no_sentence = 0
        no_bunsetsu = 0
        temp1[no_sentence] = {}

        #2次元配列(行:文番号、列:単語番号)に形態素列クラスを入れる
        for i,line in enumerate(f):
                #1行名またはEOSの場合
                if (i==0) or ("EOS" == line[0:3]):
                        no_bunsetsu = 0

                #EOSの場合
                if "EOS" == line[0:3]:
                        #srcs代入
                        for i in temp1[no_sentence]:
                                if temp1[no_sentence][i].dst != "-1":
                                        temp1[no_sentence][int(temp1[no_sentence][i].dst)].srcs.append(i)

                        no_sentence += 1
                        temp1[no_sentence] = {}
                        #print "\n【文章番号 " + str(no_sentence) + "】"

                #文節情報
                elif "*" == line[0:1]:
                        #print "\n[文節番号 " + str(no_bunsetsu) + "]"
                        tmp1 = filter(lambda w: len(w) > 0, re.split(r' ', line))
                        #インスタンスを作って文節情報のみ格納する
                        temp1[no_sentence][no_bunsetsu] = Chunk()
                        #かかり先インデックス番号を格納
                        temp1[no_sentence][no_bunsetsu].dst = tmp1[2].replace("D","")
                        no_bunsetsu += 1
                #単語
                else:
                        # "\t"か","でスプリット
                        tmp1 = filter(lambda w: len(w) > 0, re.split(r'\t|,', line))
                        #if tmp1[2]!="空白":
                        temp1[no_sentence][no_bunsetsu - 1].morphs.append(Morph(tmp1[0],tmp1[7],tmp1[1],tmp1[2]))


        #8文目の文節の文字列と係り先を表示
        text = ""
        for a in temp1[7]:
                text += "文節No " + str(a) + " 「"
                for b in temp1[7][a].morphs:
                        text +=  b.surface
                text += "」かかり先文節番号" + temp1[7][a].dst + "\n"


        print text

【実行結果】

$ sudo python 40.py
文節No 0 「この」かかり先文節番号1
文節No 1 「書生というのは」かかり先文節番号7
文節No 2 「時々」かかり先文節番号4
文節No 3 「我々を」かかり先文節番号4
文節No 4 「捕えて」かかり先文節番号5
文節No 5 「煮て」かかり先文節番号6
文節No 6 「食うという」かかり先文節番号7
文節No 7 「話である。」かかり先文節番号-1