コードネームは初話ユウ

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

ちょっと立ち止まって分析してみる

ツテをたどって、京大コーパスなるものにアクセスできたのでちょっとトライしてみた。正答率83.0%。KNBCとあまり変わらないレベル。元データがフリーでないので環境の公開はしないが、やってることとしてはcabOnKnbcと似たようなことをやっている。(IPA辞書の文節に変換して、できなかった文章は外して、etc)

 

今までは改善ネタを探すのに、誤答を出した文章をいくつか見てみてその解析結果を見て考える、というまあなんというか原始的なやり方がメインだったが、京大コーパスはKNBCよりかなり量が多く、いくつかの誤答を見ただけではちょっと対応しきれないかも(時間かけて改善して、正答数3とかしか上がらなかったら悲しい)、という気がする。なので、まずコーパスの文章はどんな感じなのか、どんな傾向があるのか、どういうところで間違えているのか、どこを修正すべきなのか等をつかむため、いくつか統計をとってみた。結果を以下にまとめてみる。

 

 

・文章あたりの文節数

 

対象とした文章の数と、それに含まれる文節の数を数えた。文節区切りはcabochaによるもの。結果:

    文章数 37027  文節数 358744

 

一文あたり9.7文節。ちなみに、1文節と2文節の文は除いてある(係り受けやる意味がないので)ため、実際にはもう少し短いはずだが、まあ大勢には影響ない。

 

・文あたり文節数の分布

 

 1-10: 0 4 1744 2494 3095  3434 3523 3356 3177 2830

11-20: 2405 2166 1803 1497 1149  933 718 558 505 342

21-30: 286 248 189 123 87  96 70 49 43 18

31-40: 19 17 7 14 8  7 4 4 2 1

41-50: 0 2 0 0 0  0 0 0 0 0

 

上の見方は、たとえば3文節からなる文章は1744個あった、ということ。コーパス中には、かぎかっこの中に引用文が複数あって句点(。)で区切られてるものもあるのだが、その辺は気にせず単純に数えている。1文節の文は除いたんじゃないの?と自分で書いててつっこみたくなるのだが、なぜ4個あるのか、原因調べてない。

 

 

・文節機能辞の品詞分布

 

全ての文節を、文節の機能辞(≒ 最後の形態素)の品詞で分類してみた。ただし助詞の場合は細分類まで見た。

 

動詞      33568

助動詞    39305

名詞      30713

副詞       8412

格助詞   112464

係助詞    39438

副助詞     3038

終助詞      162

接続助詞  11975

並立助詞   6119

副詞化     3100

連体化    52694

形容詞     5924

接続詞     4362

感動詞       52

連体詞     5516

total    356842

 

たとえば格助詞の場合なら、その文節が「XXが(/を/に/…)」の形だった、ということ。

トップ6が格助詞、連体化(ノ)、係助詞(主にハ、モ)、助動詞、動詞、名詞。この6つで86%を占める。

 

 

・誤答の係り元の品詞分布

 

係ろっとが誤答したケースについて、上と同じく係り元文節の機能辞の品詞で分類してみた。

 

動詞    4015

助動詞  2933

名詞    12757

副詞    1552

格助詞  12698

係助詞  9429

副助詞  1394

終助詞  283

接続助詞2859

並立助詞1941

副詞化  269

連体化  3143

形容詞  436

接続詞  810

感動詞  26

連体詞  198

total: 54746

 

トップ5は名詞、格助詞、係助詞、動詞、連体化。この5つで76%、約4分の3を占める。なお、このほかにフィラーとか接頭詞とかがあるため、数字は細かいところまでは合っていない。また、上の数字との比較では、最後の2文節を除くか否かとかで処理に違いがあるため、やはり細かいところは整合性がない。

 

終助詞が誤答数>総数になってて変だと思ったが、調べてみたら助詞カの細分類が「副助詞/並立助詞/終助詞」となっていて、ここの関係で数え間違いしていた。大勢に影響ないと思われるのでほうってある。

 

この数字と上のを比べると、品詞別の誤答率、なんてものも出せる。どのタイプの誤答をまずいちばんに調査するべきなのかと考えると、誤答数をみるべきか総数(誤答率)もみるべきか迷うところ。たとえば連体化助詞などは誤答数はそれなりに多いが総数も多く、誤答率としてはけっこう低い。これを修正しても、ひとつの修正で直るのはごく一部なんじゃないだろうか、などとよけいなことを考えてしまう。

 

・文あたり述語数の分布

 

 0- 9: 0 6833 10348 8240 5360   3017 1557 804 458 204 

10-19: 91 57 24 13 6   6 2 2 1 0 

20-29: 0 0 0 0 0   0 0 0 0 0

 

これの見方は、文中に1個だけ述語を持つ文が6833個あった、ということ。なんでこれを数えたかというと、格補語にせよ接続助詞にせよ「述語のみに係る」文節は多いので、誤答の多くは「述語が複数あって、そのどれに係るかを間違う」ケースが多いと思ったからである。上の数字から平均を計算すると、1文中の述語(動詞、形容[動]詞、名詞+助動詞ダ)の平均個数は3.0である。

 

 

以上から見ると、やっぱり名詞がまずそうかな。と思ってログを見ると、副詞可能タイプ(結局、当面、etc)の扱いは明らかにおかしそう。あと格助詞が多いか。格助詞については、たとえば日本語係り受けコーパス等から(名詞、格助詞、述語)の組の頻度をとってきて判定に使えば改善できるんじゃないか、などと考えたり。係助詞についても格助詞の情報が使えそうか。まあいろいろと改善点はありそうである。

 

徐々に改良中

KNBコーパスで正答率が出るようになると、やはり良い数字を出したくなる。というわけでここしばらくは正答率を上げるために係ろっとの改良作業をやっていた。

誤答を出した対象文をログ付きで解析し、ログを見て誤答の原因を割り出して修正、という作業を繰り返すわけだが、最初のうちは実際の係り受けの誤りよりも、正答チェックの環境の方にバグがあるのが見つかり、そっちを直していた。前の記事の最後で訂正が入ったのはそのため。いや見苦しくてお恥ずかしい。

2週間ほどやって、現在の状況:

      正答  誤答   正答率

係ろっと   17564      3110      85.0%

(cabocha   18113      2561      87.6%   w/v0.64, ipadic)

 

この版を v0.2 としてまた github に載せておく。


cabochaとの差 2.6%。だいぶ近づいてきた。というか、誤答と判定されたものを調べてみると、コーパスの方が間違っているものや、正解が2通り(以上)考えられて実は誤答と言えないものもけっこうな頻度であるので、実質的には差はもっと小さいと思う。

cabochaでは素性が2万個、素性を組み合わせた特徴が4万個ある。そのためソースを追っても、計算方法自体はわかるのだが、本来知りたかった「係り受けはどういう基準で判定するのか」については結局よくわからなかった。係ろっとでは評価パラメタはv0.2で51個。アルゴリズムも読めばわかる程度の簡潔さなので、係り受けの基準についてはかなり「実感として理解できる」レベルになったと思う。

現状v0.2では、品詞分類の情報しか使用してなくて、個々の単語については区別していない。(ごく一部の基本的な助詞・助動詞を除く。)この情報を使えば更に精度が上がることが期待されるので、cabochaを越えることも十分可能では、…と思っているのだが、どうなんだろう?次はこれをやってみる予定。

 * * * *

…という記事を書いてさあ投稿しようとしたら、cabochaのv0.65というのが出ていた。なのでざっと試してみた。


      正答  誤答   正答率

cabocha    19348      1326      93.6%   (w/v0.65, ipadic)


…ん?上がりすぎじゃね?w  かなり目標が遠くなった感があるが、まあ地道にやっていきますか。

KNBコーパスで正答率を測る

せっかく係り受け解析器を作ったので、やはり精度がどうなってるか気になる。ということで、測ってみることにした。

論文とか見るとだいたい皆さん京大コーパスというのを使ってるようだ。なのでこれを調べてみる。…えーと、毎日新聞CDROMてのがいるのか。これはどこで買えば… 12まん6せんえん!?誰が買うねんそんなもん。というわけで即却下。

なんか別のものがないか探してみると、KNBコーパスというのがあり、これは本文も入ってるらしい。というのでこちらに決定。ググったところ、cabocha & KNBコーパスをやってみた、という人もいた。 http://lucene.jugem.jp ただしこちらは文節区切りと固有表現が対象で、係り受けではないみたい。

KNBコーパス http://nlp.ist.i.kyoto-u.ac.jp/kuntt/KNBC_v1.0_090925.tar.bz2

でやってみたのだが、困ったのは、コーパスの文節区切りとcabochaのそれとが食い違うケースがけっこうあること。文節が違うと係り受けの比較が意味をなさなくなってしまう。でいろいろ考えて、大半のケースはうまく処理できるように工夫してみた。何をやったか、どんな比較をしたかがわかるように、これに使ったツールも公開しておく。
 https://github.com/yu-hatva/cab_on_knbc

「大半のケース」と書いたが、それでも扱いきれないケースもあるので、その場合はしょうがないので比較から除いた。約4000文のうち、150文ほどがこれで除かれた。

残りの文に対して係り受けを走らせ、各文節に対して係り先が正答か誤答かを決め、正答・誤答それぞれの文節数を数えた。文最後2つの文節は常に答えが決まってるのだが、このうち最後から2番めの文節は数え、最後の文節は数えていない。どうすべきか微妙なところだが、まあ(私のここでの)目的は cabocha と係ろっとの比較なので、とりあえず同じ基準でありさえすればいいだろう、と思っている。他のデータと比較するときは要注意。

cabocha(v0.64, IPAdic)と係ろっと双方に対してこれを行った。結果:

      正答  誤答   正答率
cabocha   17843    3532     83.4%
係ろっと  16129    5246     75.4%

8%差か。まだまだcabochaには及ばないけど、まあかなりやっつけで作ったにしては上出来ではないかと思う。ちゃんと項目考えて学習すれば追いつけそう…だろうか?

 

10/23 訂正:すみません、スクリプトに一部バグがあって計算が違っており、正答・誤答数が間違えてました。cabochaがコーパスより余分に文節区切るケースの正答がミスってました。

以下に訂正します:

 

      正答  誤答   正答率
cabocha    18472      2903      86.4%

係ろっと    16690     4685       78.0%

 

10/28 再度訂正:チェック対象の文節を一部減らします。cabochaの方が文節を細かく区切っている場合は、そこへ係るべき文節をチェックしないようにしました(コーパスだけからは正解がわからないので)。これにより約700文節が対象から外れました。新しい結果は以下になります:

 

      正答  誤答   正答率
cabocha    18113      2561      87.6%

係ろっと    16298     4376       78.8%

 

Githubの方も対応して修正しておきました。

 

【作ってみた】全域探索を行う日本語係り受け解析器「係ろっと」

できた。ソースはこちら

 

網羅的なテストまではしていないが、ざっと動かしてみたところでは、cabochaとの結果比較で9割方一致する感じ。結果が異なるものを見てみると、だいたいこっちがおかしいのだけれど、cabochaの方が間違ってることもちらほらあるようだ。cabochaの正解率が89%とのことだが(今はもうちょいよい?)、係ろっとはそれよりやや落ちるくらいだろう。(「やや」がどのくらいなのか、データを取ってみないとなんとも言えないが。)

 

気になる計算量の方だが、探索ノード数で普通の文だと数百程度。かなりの長文(30文節とか)でも数万程度で収まる。実行時間はあっという間。あまり心配することなかったようだ。

 

現状かなり簡単なルール/スコア計算しか使っていない。評価項目は「こんなもんかな」で適当に選んでるだけに近い。評価パラメタも今は手で適当につけてるだけだし、この辺はもっとまじめに項目考えてちゃんと学習させればもう少し上がるだろうとは思う。

 

とはいえ、いろいろ例題をやらせてみると「あ、こんな文章が…」というのがけっこうあり、それらにその都度(アドホックに)対処していくとけっこう余分なぜい肉がついてきた感じ。ほんとはできるだけシンプルにしたい気持ちもあるのだが。

 

意味情報を使ったりする拡張は容易になるように作っている(つもりな)ので、KNPみたいに格フレームの情報やら使えばまたもっと精度上げられるのではないかなー、と思っている。まあそれはそれで大変そうだけど。

 

****

 

ソースの使い方を中の README.txt に記しておきますので、興味のある方はぜひ使ってみてください。結果やバグレポート等歓迎します。ご質問は本ブログへコメントいただければできるだけ対応します。

 

係り受け解析器を設計する

cabochaの係り受けは、短い文だとまあまあいいものの、ちょっと長い文になるとけっこう間違う。この理由は、おそらく次の2つがあるだろう:

 

・構文と辞書(品詞)情報のみに頼っており、意味を見ていない

・決定的動作で、全域探索をしていない

 

このうち前者の意味を見る方はぱっと見大変で、すぐにはできそうな気が全然しない。が、後者の全域探索の方は、少なくとも作るだけならばそう難しくはなさそうな気がする。というわけで、

 

「構文と辞書(品詞)情報のみを使い、全域探索を行う係り受け解析器」

 

を作ってみることにする。

 

まず作る前に前例を調べてみる。cabochaはまあ大体わかった(つもりだ)が、KNPの方も見てみる。…わからん。cabochaよりかなり作りが複雑。ソースのコメントはむしろcabochaより親切に入っているのだが、いかんせん元の設計がどんなものかまったく情報がないのでちょっとお手上げ状態。cabochaのときは「段階的チャンキング」の論文があったのだが。まあ dpnd_analysis.c とか kakari_uke.rule とかをざっと見ると、多少「ああ、こんなことやってそうだな」というのが断片的にわかるところもあるので、まあそのくらいにしておく。他にEDAというのもあるようだが、あまり他のソースばっかり読んで時間とられるわけにもいかないのでこれはパス。単語ベースってことだし、文節ベースでいいだろ。

 

論文も探す。dependency parser とかでググる。shift-reduce, Eisner, MST, ILP, 等々いろいろあるようだ。全域探索が目的なので、shift-reduceは除外。他のを見てると、どうも探索の計算量がO(**)だ、とかいうあたりがいろいろ皆さん気にしてるようだ。…うーん、でもどうなんだろう。人間が読んで理解できるような文章なら、そんな計算量が必要なはずないと思うのだが(でないと人間にわからないはず)。まあまずはあまり計算量気にせずとにかく作ってみて、計算量かかって遅いようならまた考えよう、といういいかげんな気分で設計を始める。

 

論文を見てるとすべての文節の組み合わせをトライしてるようだが、少なくとも日本語書き言葉ならさすがにそこまでしなくてもいいんじゃないかと思う。連体詞なら必ず名詞にかかると思ってよいし、格補語なら必ず述語にかかるだろう。そういう「絶対こうなる」的ルールと、「大体こうなることが多いんだけど、例外もある」ようなルールとは分けられるだろう。前者をハードルール、後者をソフトルール、と仮に呼ぼう。ハードルールが適用できるなら、係り先が「(自分より右の)全ての文節」よりもかなり小さいサブセットに限定される。これプラスいくつか枝刈りの技術を組み合わせれば、探索空間は十分小さく抑えられるのではないかな、というのがまあ楽観的かもしれないが当方の予想。

 

探索のやり方もいろいろ工夫が考えられるが、まずは単純な木探索で、文末側から機械的に(ハードルールで選んだ)可能な係り先をしらみつぶしに辿っていく、という方式で行ってみる。文頭まで行ったら(つまり、木の末端では)係り受けの評価(スコア計算)を行う。ここでソフトルールが出てきて、「は」は文末にかかりやすいとか、同じ格の補語は2つ以上あれば減点とか、点数づけをしていく。

 

入出力もいるのだが、これはcabochaを流用することにしよう。cabochaが 1.形態素解析 2.文節分割 3.素性選択 4.係り受け となっていることは前に書いたが、この 2.文節分割 まではcabochaをそのまま使う。(正確に言うと、3.素性選択 の中のfindHead()の結果も使う。まあたいした処理ではないが。)cabochaのデータ構造から文節や形態素の情報をひっぱってきて解析する、とするのがいちばん楽そうだ。出力も、やろうと思えばcabochaのデータ構造に書き込んでcabochaの出力ルーチンを使うこともできるが、とりあえずはcabochaの結果と比較してどこが違うかを見たいので、テキストで文節ごとの係り先をcabochaと独自ルーチンの方と両方出す、くらいで当面はいいことにする。

 

以上のようなプログラムならそんなに難しくないだろう、ということで、作ってみる。というか実はもう作っていてだいぶ動いている。せっかくなので公開してみようか、と思うが、ちょっと現状ソースが汚いのでもうちょっと整えてからにしようか。

cabochaソースを読む(4)係り受けレイヤ

いよいよ本丸の係り受け部分を見ていく。parse() は dep.cpp l.191から。

 

アルゴリズム自体は最初の回に紹介した論文に詳しく述べられている。parse()は100行に満たないので、論文と見比べながら読んでいけば大体わかると思うが、いくつかコメント:

l.207 build()は前処理。

l.245 estimate() が「src文節がdst文節に係るか?」を判定する。

ll.255-260 は、estimateが「係る」と判定したら、互いのA/B素性をコピーしあうところ。

 

build()の定義はl.51から。ll.79-83 各文節のfeatureを、頭文字によってstatic/gap/dyn_a/dyn_bに分類している(selectorでそのように頭文字をつけていた)。ll.93-100 kをはさむ全ての(i,j)ペアについて、kのgap featureを(i,j)に対応するgap[]エントリに入れている。j(j+1)/2+iって、三角行列か。

 

estimate()はl.109。ll.122-129 dist(文節間の距離)。1/2-5/6-の3種類しか分類してないのか。まあこれでも十分なのか。ll.132-140 static。src側は頭文字'f'、dst側は大文字'F'にしている。ll.152-168 dynamic。論文の動的素性のA,B,CがそれぞれA,a,Bに対応するようだ。

で l.176 で svm->classify() を呼んで係るか否かを判定。

 

もう少し具体的に素性の使われ方(計算)を知りたいので、classify()の中を見にいく。呼び元の形は

 classify(size, char** fp)

で、fsizeは出現した4種の素性の個数の合計。fpは、fp[0]="A:の", fp[1]="DIST:6-" のような感じで各素性が入っている。

 

svm->classify()の定義はsvm.cpp l.290にある。その中でまたオーバーライドされたclassify() (l.304)を呼ぶのだが…この中でDoubleArrayとかいろいろ使っていてかなり複雑で、ちょっと読んだだけではわからなかった。うーん、困った…

 

が、svm.cppの下の方にSVMTestというクラスがあり、こちらのclassify()は読みやすい(l.563, l.571)。SVMTestとは何かよくわからないが、svm.hのコメントを見ると "used only for debugging" とある。おそらく本チャンのSVMの方は秘術を尽くした高速化バージョンで、これのデバッグを、遅いが実装が単純(で間違いが少ない)SVMTestとの比較で行っていたのではないか、と推測。もしかして違ってるかもしれんが、いちおうそう思ってSVMTestを読み進める。

 

SVMTest::classify()は非常にシンプルで、Σ w[i]*kernel() を計算してるだけ。

kernel() は svm.cpp l.25 にあるが、引数がよくわからないので、先に SVMTest::open() (l.589)を見る。ファイル ifs を開いているが、おそらくmodelディレクトリのファイルだろう。dep.ipa.txtを見てみる。このファイルのフォーマットは、最初の回に紹介した Read Cabocha ページのpdf(2番め)に解説されている。l.40345までは素性。l.40347からdegree, biasで、その次からが各ベクトルとその重み。ここまで押さえた上でSVMTest::open()を見直すと、w_とx_がそれぞれ重みとベクトル(素性IDの並び)であることがわかる。

 

svm.cppに戻ってkernel()を見る。whileループがちょっとわかりづらいが、x1/x2がソートされた素性ID列なので、一致する素性の数を数えていることがわかる。0/1の変数のベクトルの内積(dot)をとってる、というか。返しているのは 

(1 + dot(x1,x2)) ^ deg

である。ちなみにdep.ipa.txtではdeg=2である。

 

以上でひととおりcabochaの係り受け判定の計算方法は大体わかったので、このシリーズはひとまず終了。

cabochaソースを読む(3)各文節の素性

素性選択レイヤを見る。ソースはselector.cpp。l.117 parse()から行く。

 

l.121 の forループで(sentence中の)全chunkをなめる。

l.128 の forループで各chunkの中の全tokenをなめる。

各tokenに対して、

 

l.130 pat_kutouten_.match(token->normalized_surface)

これは何だろうか。parse()のすぐ上にSelector::open()があり、ここで

 

  CHECK_DIE(pat_kutouten_.compile(KUTOUTEN_PAT, &iconv));

 

としている。open()というくらいだから最初に1度呼ぶんだろう。この KUTOUTEN_PAT は、ソースの selector_pat.h の中で

 

// const char KUTOUTEN_PAT = "(。|、|,|.)";

 

のように定義されている。

match()の中身は追っていないが、まあパターンマッチしてくれるのだろう。

parse()に戻って、ll.130-143は、句読点・[開閉]かっこのパターンが見つかると片っ端から出力しているのがわかる。

 

素性選択レイヤの出力は↓こんな感じだが

 

* 3 -1D 0/1 0.000000 F_H0:本,F_H1:名詞,F_H2:一般,F_F0:を,F_F1:助詞,F_F2:格助詞,F_F3:一般,A:を,B:名詞-一般,G_CASE:を

 

G_PUNC:** や F_OB:** もこのような素性の例である。 

また、この"G_"とか"F_"とかは何か意味があるのかと気になるのだが、これもまた後ほど述べる。

 

l.148 findHead() の定義は下の l.238 にある。この関数は、文節の「主辞」と「機能辞」の位置を返す。中を見よう。

 

l. 253 head_matcher = &pat_ipa_head_;

のような行があるが、pat_ipa_head_ も pat_kutouten_/KUTOUTEN_PAT と同様 selector_pat.h に定義があり、

 

// const char IPA_HEAD_PAT = "!(助詞|助動詞|動詞,非自立|動詞,接尾|形容詞,非自

立|形容詞,接尾|空白|記号)";

 

要はこれらの品詞以外、つまりいわゆる自立語にマッチするようだ。ちなみに機能語は次のとおり:

 

// const char IPA_FUNC_PAT = "(助詞|助動詞|動詞,非自立|動詞,接尾|形容詞,非自立|形容詞,接尾)";

 

ll.266-271 を見るに、これらのパターンにマッチする自立語・機能語のうち、文節中の最後に表われるものをそれぞれこの文節の主辞・機能辞と判断し、その定義を返す。たとえば「約3キロ」なら最後の「キロ」が主辞になる、ということか。「転覆しそうだったのだけれど」なら最後の「けれど」が機能辞になる、と。係り受けを決定するのには「係り元の機能辞 -> 係り先の主辞」が重要なので、こうするのが効果的、ということなのだろう。

 

parse()に戻って、l.150あたりから。hXXは主辞(head)、fXXは機能辞(func)に関わる。

 

155    const char *hctype   = get_token(htoken, pos_size);

156    const char *hcform   = get_token(htoken, pos_size + 1);

 

pos_size は l.119で定義されてて、辞書がIPAなら4。IPA辞書では入力が

 

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

 

こうなので、[4]=段・マ行 [5]=連用タ接続 のようになるはず。つまりctypeが活用種類、cformが活用形だろう。

 

ll.195-205:

    if (pat_dyn_a_.prefix_match(ftoken->feature)) {

      ostrs << " A:" << fsurface;

    } else if (fcform) {

      ostrs << " A:" << fcform;

    } else {

      concat_feature(ftoken, pos_size, &output);

      ostrs << " A:" << output;

    }

 

    concat_feature(htoken, pos_size, &output);

    ostrs << " B:" << output;

 

 

また変なのが出てきた。pat_dyn_a_/DYN_A_PAT も selector_pat.h にあって、

 

// const char DYN_A_PAT = "(助詞|副詞|連体詞|接続詞)";

 

concat_feature()はutils.cppにあり、あるtokenのfeatureを全部ハイフンでつなげる。

 

つまり"A:"素性とは、機能辞が「これら4つのどれかの品詞なら文字列そのもの、活用語ならその活用形、それら以外なら品詞情報」となる。また"B:"素性とは「主辞の品詞情報」となる。

 

このA, Bとは何ぞや?は、係り受けparserを読まないとわからないのだが、先に簡単に説明しておくと、A素性とは「ある文節に既に係っている係り元の情報」、B素性は「ある文節から既に係っている係り先の情報」のことである。最初の回に挙げた論文にこの辺のことが「動的素性」として説明されているので参照のこと。

 

これは多分、「ひとつの述語にヲ格の補語は2つはつかない」のような制約をうまく表現できるのだろう。

 

selectorの段階ではまだどの文節がどの文節に係るかわかっていないが、まずは文節Xに対して「もしXが別の文節Dに係ったときは、DにつけるであろうA素性」と「もしXが別の文節Sから係られたときは、SにつけるであろうB素性」をリストアップしておく、という作業をselectorで行っているわけである。

 

ついでなので、最初の方で G_PUNCとかF_OBとか出てきたが、このG_やF_にも触れておく。G_は"gap feature"を表す。これは、「文節Sが文節Dにかかるとき、SとDの間に位置する文節の持つ情報」のことである。たとえば「私は彼の無垢な、あふれんばかりの才能に(ひそかに)嫉妬していた」という文で、「私は」が「嫉妬していた」に係るか?を考えるとき、途中に読点があるのでG_PUNCが、また開・閉かっこがあるので G_OB, G_CB がつくことになる。

 

F_は static feature といって、これは文節自体の持つ特徴である。

 

このように、cabochaではfeatureはstatic/gap/dyn_a/dyn_bの4種類ある。

これらをどのように使用しているか、は次回係り受けレイヤで見ていく。

 

 * * * *

ところでふと気づいたが、cabocha, KNP以外の係り受け解析器もあるみたい:

 

驚異的な解析速度を誇る日本語係り受け解析器

 

暇があったらみてみようか…まあそうそう他人のソースばかり読んでもいられないが。