読者です 読者をやめる 読者になる 読者になる

コードネームは初話ユウ

自然言語処理でいろいろやってみる

cabochaソースを読む(2)入力データから情報抽出

前記事の続き。

tree->read() (tree.cpp l.406) が文字列入力からデータ構造を構築する。まずデータ構造の宣言をチェック。

 

cabocha.h に struct cabocha_chunk_t (l.75), struct cabocha_token_t (l.87) の宣言がある。chunk が文節、token が形態素。ちなみにこれらはそれぞれ Chunk, Token に typedef されている。

 

さてtree->read() を見る。入力は文節区切りとするので、switch文はINPUT_CHUNKを想定。

 

l.435 の while がメインループだが、この中は l.438 の if 文により大きく2つに分かれる。

 

入力フォーマットはこんな感じなので

 

* 2 -1D

読ん    動詞,自立,*,*,五段・マ行,連用タ接続,読む,ヨン,ヨン

で      助詞,接続助詞,*,*,*,*,で,デ,デ

 

要はif文の前半(l.486のelseの前)は'*'ではじまる「文節情報」の行の処理であり、後半は各形態素の行にあたる。

 

前半の方から。l.439 の tokenize() は、定義は utils.h にあるが、文字列を指定された分割文字(この例だと空白)でトークンに分割するものである。(ここの"token"は形態素ではないので注意。)上の例では、char* column[] の column[0] に最初のトークン '*' が、column[1]に次のトークン '2' が、というふうに入る。

 

l.444 add_chunk() は treeの中に文節スロットを追加する。定義はl.338にある。文節の情報はここに入る。

 

コードでは文節の情報をいろいろセットしているが、入力が文節区切りならばほとんど関係ない情報ばかりである。参考までに書いておくと、素性選択や係り受けの出力においては、各columnは次の情報が入る:

 

 column[0] '*' 固定

 column[1] 文節番号

 column[2] 係り先文節番号

 column[3] 主辞/機能辞の位置

 column[4] 係り受けスコア

 column[5] 素性情報

 

if文後半、形態素の方。l.487 はまた tokenize()。今度は分割文字がタブなのに注意。上の入力フォーマットで「読ん」の次がタブなのだ。つまりここでは

 column[0] 読ん

 column[1] 動詞,自立,*,*,五段・マ行,連用タ接続,読む,ヨン,ヨン

のようになる。なおこのcolumn[1]の内容は、mecabの辞書のエントリ内容ほとんどそのままである。

 

l.490 add_token() は add_chunk() と同様、treeへのスロット追加。surface は形態素の文字列そのもの。normalized_surface は「正規化された」文字列。normalize()のコードはちゃんと追ってはいないが、ソースの normalizer.rule からして、全角/半角表記を統一するものだろう。

 

l. 497 token->feature には column[1]、つまりコンマ並びが入るが、l.505 feature_list には l.502 tokenizeCSV() でコンマを分割したものが入る。tokenizeCSV()はtokenize()と同様の動作、ただし分割文字がコンマになる。つまり上の例では

 feature_list[0] 動詞

 feature_list[1] 自立

のようになる。

 

次回は素性選択レイヤを見る。