「日本語形態素解析」学生実験テキスト 筑波大学情報メディア創...

Preview:

Citation preview

「日本語形態素解析」学生実験テキスト筑波大学 情報メディア創成学類・情報科学類

山本幹雄

2016.9

概要

自然言語処理とは日本語や英語のように人間が使用する言語で書かれたテキストを計算機で処理する技術である。本実験では、日本語テキストを対象とした単語分割(専門用語では形態素解析という)の実験を行う。日本語テキストは英語等とは異なり、テキスト中の単語境界が明示的ではなく、何をするにもまず単語に分割する必要があるため、日本語単語分割技術は高度な日本語自然言語処理の基本技術となっている。本実験の目的は以下の 2つを体験的に学習することである。• 様々な日本語単語分割法• 辞書を計算機上で実装するためのデータ構造とアルゴリズム具体的な課題は、いくつかの分割手法を用いた日本語単語分割システムの作成と、その応用として日本語テキストを入力とする簡単な日英辞書引きシステムを作成することである。様々な単語分割手法があるが、本実験では、以下のような単語分割手法を取り上げる(実際に作成するのは “*”が付いた3つ)。• 字種による分割*• 最長一致法による分割*• 単語数最小法による分割• 文節数最小法による分割• コスト最小法*• 確率的形態素解析実装に関しては、計算機上での辞書の実装方法(トライや二分探索)が重要である。本実験を通して、基本的なデータ構造とアルゴリズムの理解を深める。

1 自然言語処理と単語分割自然言語処理とは人間が日常使用する日本語や英語のような言語で書かれたテキストを計算機処

理する技術のうち、意味内容まで少し踏み込むという意味でやや高度なものを言う。自然言語処理の応用は多岐に渡るが、最近では情報ネットワークの発達に伴う情報過多に対処するための支援システムとして期待されている。インターネットでは、マルチメディアによる情報伝達が注目されているが、最も多くの知識・情報を表現しているメディアが自然言語であることには変わりはない。自然言語で書かれた多量の文書を効率的に変換(翻訳)・検索・要約・抽出・分類する自然言語処

1

理技術は これからの情報ネットワーク時代に欠かせないものとなると考えられている。ワードプロセッサ(ワープロ)は自然言語処理システムとは言わないが、最近のワープロには翻訳機能や要約機能、推敲支援機能等を持つものもあり、これらは自然言語処理を要素技術として使っていると言える。自然言語処理の唯一最大の問題は自然言語文の持つ曖昧性である。ただし、ここでいう「曖昧

性」とは、一般に人間が「曖昧な文」と感じる場合の曖昧性とはニュアンスが異なる。人間が感じる自然言語の曖昧性はかなりレベルが高いものであり、機械処理においてまず問題となるのは、人間が気付いてもいないレベルの曖昧性である。人間は大量の背景知識・常識と高度な状況処理能力によって多くの曖昧性を無意識のうちに解決している。自然言語を機械処理してみてはじめて、意識していなかった自然言語の曖昧性に気づくのである。例えば、本実験のテーマでもある単語分割について、次のような例文を考える。

「赤い四角の上の三角を青い積み木の上に置け。」

この文章は普通の人間であれば、若干の意見の相違はあるかもしれないが、おおよそ次のような単語から成っていると考える。左から、文章の単語、読み、原形、品詞である。

赤い (あかい) 赤い 形容詞四角 (しかく) 四角 普通名詞の (の) の 格助詞上 (うえ) 上 普通名詞の (の) の 格助詞三角 (さんかく) 三角 普通名詞を (を) を 格助詞青い (あおい) 青い 形容詞積み木 (つみき) 積み木 普通名詞の (の) の 格助詞上 (うえ) 上 普通名詞に (に) に 数詞置け (おけ) 置く 動詞。 (。) 。 句点

この分割は成人している人間にとってきわめて容易である。しかし、機械ではそうは行かない。以下は 10万単語レベルの辞書を持つシステムが出力した、単語の候補(の一部!!)である。

2

赤い (あかい) 赤い 形容詞赤 (あか) 赤 普通名詞い (い) いる 動詞四 (よん) 四 数詞四角 (しかく) 四角 普通名詞四角 (よつかど) 四角 普通名詞角 (かど) 角 普通名詞角 (つの) 角 普通名詞の (の) の 格助詞の (の) の 名詞接続助詞上 (うえ) 上 普通名詞上 (かみ) 上 普通名詞の (の) の 格助詞の (の) の 名詞接続助詞三 (さん) 三 数詞三角 (さんかく) 三角 普通名詞三角 (みつかど) 三角 普通名詞三角 (みすみ) 三角 地名角 (かど) 角 普通名詞角 (つの) 角 普通名詞を (を) を 格助詞

青い (あおい) 青い 形容詞青 (あお) 青 普通名詞い (い) いる 動詞積 (せき) 積 普通名詞積み (つみ) 積む 動詞積み木 (つみき) 積み木 普通名詞み (み) み 名詞接頭辞み (み) み ナ形容詞接頭辞み (み) みる 動詞木 (き) 木 普通名詞の (の) の 格助詞の (の) の 名詞接続助詞上 (うえ) 上 普通名詞上 (かみ) 上 普通名詞に (に) に 数詞に (に) に 格助詞に (に) に 名詞接続助詞に (に) にる 動詞置け (おけ) 置く 動詞置け (おけ) 置ける 動詞。 (。) 。 句点

この中から正しい単語列を選ぶのであるが、常識というものを持たない機械にとっては、これが思いのほか苦手である。これは、かな漢字変換がよく間違えるのと理由は同じである。自然な日本語というものがどういうものかの知識がなければ、とんでもない組み合わせを出力する。例えば、できのよくない単語分割システムは以下のような単語列を上記の単語候補から選択する。

3

赤* (あか) 赤 普通名詞い* (い) いる 動詞四角 (よつかど)* 四角 普通名詞の (の) の 名詞接続助詞上 (うえ) 上 普通名詞の (の) の 格助詞*三角 (さんかく) 三角 普通名詞を (を) を 格助詞青* (あお) 青 普通名詞い* (い) いる 動詞積み* (つみ) 積む 動詞木* (き) 木 普通名詞の (の) の 名詞接続助詞上 (かみ)* 上 普通名詞に (に) に 数詞*置け (おけ) 置く 動詞。 (。) 。 句点

‘*’が付いている箇所は間違いである。「赤い」という形容詞の活用語尾「い」を「いる」という動詞の連用形と間違ったり、「積み木」を「積む」の連用形と「木」の組み合わせと解釈している。「積み木」の例では、「荷を積み (,)木を切り倒せ」のような文を考えた場合、「積み」と「木」で分割することが妥当であるため、周りの文脈を見ずに、1単語とするか、2単語とするかを決定できない(もちろんこの例文の場合「積み」と「木」の間に読点を入れるのが普通であるが、絶対に入れるとは限らない)。人間は、日本語としての自然性の知識を無意識のうちに使い、苦もなく(読点がないと少し悩むかもしれないが)文全体からどちらかを決定できる。機械に同じことをやらせるには、人間が無意識に使っている知識を明示的に取り出し、プログラ

ムに埋めこむ必要がある。無意識に使っている知識を明示的かつ体系的に取り出すことは容易ではなく、人間が使用している知識は膨大な量であることが知られている。また、完全な分割システムを構築するには、機械がいわゆる文の「理解」をする必要があるが、これは現状の技術では困難である。このため、現在最高レベルの日本語分割システムでも 99%程度の正解精度*1である。すなわち、100単語に1つくらいは間違う。本実験では、効果的な手法として知られている手法の簡易版を用いて、区切りだけの正解精度で 90%以上の正解精度を目指す。

*1 この場合の正解精度とは、システムが分割し、出力した単語のうち正しかった単語の割合である。ただし、単語区切りだけでなく品詞等の付加情報に関しても正解してはじめて正しい単語に区切れたとみなした場合の数値である。

4

2 日本語単語分割手法日本語の単語分割手法は 1960年代から精力的に研究されており、以下のようなさまざまなもの

が提案されている。

• 字種による分割• 最長一致法• 単語数最小法• 文節数最小法• コスト最小法• 確率的形態素解析

最初の「字種による分割」以外は辞書を用いる手法である。以下の節で各手法を解説する。最後の「確率的形態素解析」は「コスト最小法」の確率論的な見地からの再形式化であり、やや高度なので本実験では取り上げない。

2.1 字種による分割

ここでいう字種とは、漢字、平仮名、片仮名、アルファベット、記号等の字の種類のことである。日本語の名詞の多くは、単一の字種で書かれることが多い。例えば、本節の最初の2文には、

「字種」、「漢字」、「平仮名」、「片仮名」、「アルファベット」、「記号」、「字」、「種類」、「日本語」、「名詞」、「単一」

といった名詞が含まれるが、漢字だけかアルファベットだけから構成されている。日本語の文は半分程度は名詞であろうという推測から字種が変化する場所を単語の区切りとする方法が「字種による分割」である。この考え方で、本節の最初の2文を区切ってみると以下のようになる。

「ここでいう/字種/とは/、/漢字/、/平仮名/、/片仮名/、/アルファベット/、/記号等/の/字/の/種類/のことである/。/日本語/の/名詞/の/多/くは/、/単一/の/字種/で/書/かれることが/多/い/。」

非常に単純な方法の割には、おおよそ妥当で、特に名詞に関してはよい結果のように思える。動詞や形容詞に関しても、活用しても変化しない語幹の部分を単語として認めればおおよそ正しいと言える。しかし、1章の例は、以下のようになってしまう。

「赤/い/四角/の/上/の/三角/を/青/い/積/み/木/の/上/に/置/け/。」

「積み木」は3つの単語に分割されてしまうし、後半はすべて1文字の単語と見なされている。あまりよい結果とは言えない。

5

この手法のもう一つの大きな問題は、単語分割だけでは様々なアプリケーションにとって不十分な点である。たとえばWWW上の情報検索システムのインデックスとして、各文書から名詞だけをキーワードとして取り出したい場合、この手法では分割された単語の品詞が分からないので、どれが名詞であるかの情報が得られない。また、動詞や形容詞については、活用によって語尾変化するため、同じ意味の単語が活用によって異なる単語と見なされてしまう。活用する単語に関しては基本型(「置け」であれば「置く」)の情報が必要である。さらには、日本語テキストの音声読み上げシステムでは、各単語の読みが必要であるが、この手法ではこれも出せない。一般に、自然言語処理の前処理としては、単語の分割の他、上であげた「品詞」、「原形」、「読み」の情報を付加することが重要である。これらの付加情報を得るためには、単語辞書が必要である。以下の節では、単語辞書を使い、性能を上げながら、付加情報を付与する手法を解説する。

2.2 最長一致法

1章の例から「青い積み木」の部分を考える。この部分から単語辞書を引いて取り出される候補の単語は以下のようになる。

青い (あおい) 青い 形容詞青 (あお) 青 普通名詞い (い) いる 動詞積 (せき) 積 普通名詞積み (つみ) 積む 動詞積み木 (つみき) 積み木 普通名詞み (み) み 名詞接頭辞み (み) み ナ形容詞接頭辞み (み) みる 動詞木 (き) 木 普通名詞

このうち、「青い」と「積み木」が正解であるが、これは最も長い単語を選んでいると言える。以下のような観察が得られる。

「辞書に載っている単語のうち、最も長い単語が正解である可能性が高い」

この観察を利用した最も単純な方法が「最長一致」による単語分割である。アルゴリズムは単純で、まず文の頭から始まる文字列のうち、辞書にある単語をすべて調べる。その中から、最も長いもの(最長一致)を最初の単語と決定し、決定された単語の次から始まる単語を同様に決定していく。最も長い単語が複数あった場合は、ランダムに選ぶか、品詞の出現頻度の高いものとする。品詞の出現頻度は、分析したデータに依存するが、おおよそ以下のような順序で出現頻度が高い。

1. 助詞2. 名詞

6

3. 動詞4. 記号 (句読点など)5. 助動詞6. 接尾語7. 数字8. 副詞9. 形容動詞10. 形容詞11. 連体詞12. 接続詞13. 接頭語14. 感動詞

もっと大量の日本語テキストから統計データが得られる場合は、単語そのものの出現頻度を使うともっと性能を向上させることができる。先頭から最も長い単語、複数あった場合は出現頻度の多い品詞を持つ単語を優先させた場合の 1

章の例文の解析結果は以下のようになる。

赤い (あかい) 赤い 形容詞四角 (よつかど)* 四角 普通名詞の (の) の 格助詞*上 (うえ) 上 普通名詞の (の) の 格助詞*三角 (さんかく) 三角 普通名詞を (を) を 格助詞青い (あおい) 青い 形容詞積み木 (つみき) 積み木 普通名詞の (の) の 格助詞*上 (うえ) 上 普通名詞に (に) に 格助詞置け (おけ) 置く 動詞。 (。) 。 句点

ほぼ完璧であるが、「の」に関して「格助詞」を「名詞接続助詞」より優先させたため品詞が誤っているし、「四角」の読みが「よつかど」となっている。しかし、細かい品詞の分類や読みが必要ない場合は、これで完璧である。この手法ではうまく解析できない例文は以下である。

「その日直方体について学んだ。」

7

これを最長一致法で解析すると以下のようになる。

「その/日直/方/体/に/ついて/学んだ/。」

正解はもちろん、

「その/日/直方体/に/ついて/学んだ/。」

である。敗因は、文全体を見ずに文頭から長い単語を決定してしまったことである。「日」以下の解析のところで、長い単語である「日直」を選択することを我慢して「日」を選べば、その次の段階で長い単語「直方体」を得ることができたはずである。解決策として、先頭から単語を決定するのではなく、決定は保留して、文全体で長い単語を選択するようにした手法が次の「単語数最小法」である。

2.3 単語数最小法

手法の名前から分かるように、「単語数最小法」は単語分割したときに、文全体の単語数が最小になるような分割を優先する方法である。単語数を最小にするということは、できるだけ長い単語を選ぶことを意味するが、文全体を見て決定する点が前節の最長一致法と異なる。この手法を理解するために、各文字位置から辞書を引き、見つかった単語候補をすべて列挙した

図を考える。この図を単語ラティスと呼ぶ。前節で考えた例文の一部「その日直方体」を考えた場合の単語ラティスを図 1に示す。単語ラティスから、入力文全体を覆う適切な単語候補列を見つけることが単語分割の仕事である。この例では、入力全体を覆う候補単語の列は3つの可能性がある(図 1下)。単語数が最小となる分割を優先すると、「その日直方体」に対しては、単語数が3となる単語分割候補3を優先する(この場合、正解)。単語数最小法は、文全体を見て最も妥当な分割を得る方法であるため、最長一致法よりも性能が

改善される可能性が高いが、計算コストが増加する。各文字位置で、M 個の単語候補が辞書から得られるとし、入力文が N 文字からなっているとする。このとき、文全体の単語分割の可能性の数は、各文字位置で M個の候補から1つの単語を決定する必要があるため、MN 個の組み合わせの中から正しい分割を得ることになる。1章の例を見れば分かるように、10万単語規模の辞書を使うと M は少なくとも 2程度にはなる。また、新聞記事の文章はやや長めで平均で 50文字程度はある。すると、MN = 250 は 1000兆を越える数となる。現代の計算機は 10年前に比べてもはるかに高速であるが、一文ごとに 1000兆もの組み合わせを調べていては非効率である。この問題を高速に解決する手法が、ビタービアルゴリズムである。ビタービアルゴリズムは動的

計画法の一種であり、以下のようなアイデアに基づく。

文頭からある分割候補箇所 xの間の文字列を考える。この文字列に対して、単語数最小とする分割が求まっているとし、かつ全体の単語数最小分割が分割箇所 xを含むとすると、すでに求まっている文頭と xの間の単語数最小分割は、全体に対しても単語数最小分割である。

8

図 1 「その日直方体」の単語ラティスと可能な単語分割集合

文頭と x の間の単語数最小分割が求まっており、その数を K とする。もし、全体の単語数最小分割が xを含むとすると、全体の単語数は、まだ求まっていない「xの直後から文末までの最小単語数」に K を足したものとなる。ここで、文頭と x の間の分割をすでに求まっている単語数最小分割と異なる分割としてしまうと、その単語数は K より大きくなることはあっても小さくなることはあり得ないため、全体の単語数も小さくなることはあり得ない。よって、文頭と xの間の単語数最小分割は、全体の単語数最小分割に必ず含まれる(もちろん、全体の分割が xを含む場合に限られるが)。図 1の例で考えると、もし全体の文字列「その日直方体について学んだ。」の分割が文字位置 6

の直後を含む場合、文頭から文字位置 6までの最適分割(図 1中の単語分割候補 3)を必ず含む。また、もし文字位置 4の直後を全体の分割が含むとする場合は、「その日直」の最小単語分割である「その/日直」(図 1中の単語分割候補 2の一部)を全体が含むことになる。この場合誤りとなるが、文全体で最適化するため、局所的に単語数が少ない誤った分割が選択される可能性は低くなる。全体の最適分割を求めるには、x を1文字づつ文末に向けて移動させていけばよい。ある文字位

置 x に関して、文頭から x までの単語数最小分割を求めるには、これまで求まっている文頭からyまで (y < x)の単語数最小分割したときの単語数を N(y)とすると、次のようにすればよい。まず、xで終わる単語の候補 w1, w2, ..., wn を集めてくる。それぞれの単語の開始位置を y1, y2, ..., yn

とすれば、文頭から yi までの単語数最小分割はすでに求まっているので、単語 wi を採用した場合

9

の文頭から xまでの最小分割数 N′(x, wi)は、次のように求まる。

N′(x, wi) = N(yi) + 1

N′(x, wi) の中で最小となる値が、文頭から x までの単語数最小分割時の単語数 N(x) であり、N′(x, wi)を最小とする wi と文頭から yi までの単語数最小分割を合わせた分割が、文頭から x までの単語数最小分割である。

x を 1 からはじめて文末に向けて移動させながら、上記のアルゴリズムを繰り返せば、文末に至ったときに、文全体の単語数最小分割が求まる。文末に至ったときに、単語数最小分割の単語列を出力するためには、各 N(x)の計算時に、最小の N′(x, wi)を与える wi と yi を各 xごとに記憶しておけば、長さ Lの入力文としたときに x = Lから文頭に向けて、再生することができる。以上の手法を厳密に記述すると以下のようになる。まずは、単語数最小法による単語分割問題の

定義である。

問題の定義:単語数最小法長さ Lの入力文字列: SL = c1, c2, c3, ..., cL(ci は文字).入力の部分文字列: Sj

i =入力文字列中の i番めから j番めの部分文字列.単語 wの表記: str(w) = 単語 wの表記文字列.単語 wの表記の長さ: |w| =単語 wの表記 str(w)の長さ(文字数).

辞書: dic(w) =

{1 if str(w)が辞書の中にある0 otherwise

.

単語列: W = w1, w2, ..., w|W|, ここで、dic(wk) = 1.単語列W の長さ: |W| = W 中の単語の数.単語列W の表記: str(W) = W の各単語 wk の表記 str(wk)を接続した文字列.

単語数最小法による入力文字列 SL の単語分割:

W = w1, w2, ... = arg minW:str(W)=SL

|W| .

次は、Viterbi アルゴリズムによる上記問題の解法である。以下のアルゴリズムでの各変数は、文頭から文字位置 xまでの単語数最小分割による(部分)単語分割をW ′ としたとき、次のような意味を持つ値を格納している。W ′ の単語数を N(x)、W ′ の最後(右端)の単語をW(x)、同様に最後の単語の開始文字位置(入力文字列中の)を B(x)に格納しながら、計算が進む。argは引数の値を返す。例えば、argi mini,j f (i, j)のような場合、最小の f (i, j)となる iを返すことを意味する。

Viterbiアルゴリズムによる W の計算(単語数最小法)(1) 初期化

N(0) = 0

10

表 1 Viterbiアルゴリズムによる単語数最小分割の計算

x 0 1 2 3 4 5 6

N(x) 0 ∞ 1 2 2 3 3W(x) – – その 日 日直 方 直方体B(w) – – 1 3 3 5 4

for i = 1 to L do, N(i) = ∞ (実際には Lを代入しておけばよい)

(2) 繰り返し: x = 1〜L

N(x) = min{w,i|dic(w)=1,Sx

i =str(w)}N(i − 1) + 1.

W(x) = argw min{w,i|dic(w)=1,str(w)=Sx

i }N(i − 1) + 1.

B(x) = argi min{w,i|dic(w)=1,str(w)=Sx

i }N(i − 1) + 1.

(3) 終了

M = |W| = N(L)

wM = W(L).

i(M) = B(L) :wM の開始位置.

(4) バックトラック

wk = W(i(k + 1)− 1)

i(k) = B(i(k + 1)− 1)

}k = M − 1, M − 2, ..., 1.

Viterbiアルゴリズムによる「その日直方体」の最小単語数分割の計算の様子を表 1に示す。これは上記アルゴリズムの (2)繰り返しの中で計算された N(x),W(x),B(w) の値をまとめたものである。 「(2) 繰り返し」中の x の各段階において計算される各変数(N, W, B)を細かく説明すると以下のようになる。x = nのとき、x = 0〜n − 1の各変数の値(少なくとも N)は確定していることに注意せよ。

x = 1のとき: 文字位置 1で終わる単語は図 1を見ると存在しない(あるとしたら、「そ」という単語であるがこれは辞書にのっていなかったと仮定する)。このため、N(1)は初期化のままの値(N(1) = ∞)となる。W(1), B(1)は未定義のままである。

x = 2のとき: 文字位置 2で終わる単語は、「その」と「の」の2つである。この2つの単語の直前の文字位置はそれぞれ、0と 1であるから、N(0) + 1 = 1と N(1) + 1 = ∞が比較され、

11

文字位置 2の直後を単語境界とする場合は、「その」の方を選択した方が単語が少なくなることが分かる。W(2)には「その」、B(2)には「その」の開始文字位置を格納する。

x = 3のとき: 文字位置 3で終わる単語は、「日」のみであり、「日」の直前の文字位置は 2であるため、N(3) = N(2) + 1 = 2, W(3) =「日」, B(3) = 3となる。

x = 4のとき: 文字位置 4で終わる単語は、「直」と「日直」の2つであり、それぞれの直前の文字位置は 3と 2である。N(3) + 1 = 3と N(2) + 1 = 2を比較すると、「日直」を選んだ方が単語数が少なくなるため、文字位置 4の直後を単語境界とする場合は、「日直」を選択すべきでぁり、このとき文頭から文字位置 4までの最小単語数は 2である。この 2を N(4)の値として格納する。

x = 5のとき: 文字位置 5で終わる単語は、「方」のみであり、「方」の直前の文字位置は 4であるため、N(5) = N(4) + 1 = 3, W(5) =「方」, B(5) = 5となる。

x = 6のとき: 文字位置 6で終わる単語は、「体」と「直方体」の2つであり、それぞれの直前の文字位置は 5と 3である。N(5) + 1 = 4と N(3) + 1 = 3を比較すると、「直方体」を選んだ方が単語数が少なくなることため、文字位置 6の直後を単語境界とする場合は、「直方体」を選択すべきである。N(6) = N(3) + 1 = 3, W(6) =「直方体」, B(6) = 4となる。

最後に最小単語となる単語分割を、文末位置から逆にたどって再構成する。上の例では文末位置を 6と仮定しているため、N(6)の値が最小単語数であり(この場合 3)、3番目の単語が「直方体」であることがW(6) の値から分かる。先頭から2番目の単語は、「直方体」の直前の文字位置、すなわち B(6)− 1 = 3の直後で分割すると仮定した場合の最適単語W(3) =「日」であることが分かる。1番目の単語は B(3)− 1 = 2から、W(2) =「その」であることが分かる。B(2)− 1 = 0

であるため、「その」の前は文頭である。以上の結果から、最小単語分割された結果は、先頭から

「その」、「日」、「直方体」

であることが計算された。最後に単語数最小法でうまくいかない例を示す。

「花子を家におくりました。」

これを単語数最小法で解析すると以下のようになる。

花子 (はなこ) 花子 固有名詞を (を) を 格助詞家 (いえ) 家 普通名詞におくり (におくり) 荷送り 普通名詞ました (ました) 真下 普通名詞。 (。) 。 句点

12

「荷送り」は新明解国語辞典(三省堂)にのっている立派な名詞である。また、「ました」に関して、名詞としての「真下」と、助動詞としての「まし +た」があるが、名詞の方が頻度が多いので「真下」になっている*2。この問題は、「文節数最小法」で改善され、「コスト最小法」で解決される。

2.4 文節数最小法

文節数最小法は、単語数ではなく文節の数を最小とする分割基準である。文節の定義を厳密に行うことは難しいが、ここでは一つの自立語の前後に任意の数の付属語が接続したものであると定義する。自立語とは名詞、動詞、形容詞等のそれだけで意味を持つ単語、付属語とは助詞、助動詞、接辞等のそれだけで意味を持たない単語である。例えば、前節で述べた「花子を家におくりました。」であれば、「花子を」, 「家に」, 「おくりました」が文節に相当する。上記の文節の定義を用いれば、ある単語分割における文節数はその単語分割中の自立語の数と等

しい。W の長さ(単語数)ではなく、W 中の自立語数に対して最小化するように単語数最小法の枠組みを変更すると文節数最小法となる。

問題の定義:文節数最小法

自立語関数: jiritsu(w) =

{1 if wが自立語0 otherwise

.

文節数最小法による入力文字列 SL の単語分割:

W = arg minW:str(W)=SL

|W|

∑i=1

jiritsu(wi) .

Viterbiアルゴリズムも同様であり、「(2) 繰り返し」のステップを以下のように変更することで、文節数最小法の Viterbiアルゴリズムが作成できる。

(2) 繰り返し: x = 1〜L

N(x) = min{w,i|dic(w)=1,Sx

i =str(w)}N(i − 1) + jiritsu(w).

W(x) = argw min{w,i|dic(w)=1,str(w)=Sx

i }N(i − 1) + jiritsu(w).

B(x) = argi min{w,i|dic(w)=1,str(w)=Sx

i }N(i − 1) + jiritsu(w).

単語数最小化法でうまく行かなかった前節の例文「花子を家におくりました。」が、文節数最小

*2 品詞の頻度ではなく、単語の頻度を使えば、「真下」を「ました」と平仮名表記する場合より、助動詞としての「ました」の方がはるかに多いのでこの問題は解決される。しかし、「ましたにある」のような場合も助動詞「ました」を優先してしまうことになる。

13

法では改善される。

花子 (はなこ) 花子 固有名詞を (を) を 格助詞家 (いえ) 家 普通名詞におくり (におくり) 荷送り 普通名詞ました (ました) 真下 普通名詞。 (。) 。 句点

という分割では、自立語数が4である。これに対して、正しい分割である

花子 (はなこ) 花子 固有名詞を (を) を 格助詞家 (いえ) 家 普通名詞に (に) に 格助詞おくり (おくり) 送る 動詞ました (ました) ました 助動詞。 (。) 。 句点

は、自立語数3で上記の誤った例は出力されなくなる。しかし、「におくり」の部分を一つの名詞と見なしても、全体の自立語数は3のままであり、依然「におくり」を一つの単語と出力される可能性は残る。これを解決するには、言語学的な知識を導入して「日本語らしさ」の観点から単語分割を評価する必要がある。

2.5 コスト最小法

「家におくりました」の部分は、「家/におくり/ました」と分割するより、「家/に/おくり/ました」と分割する方が自然である。それぞれの分割は、品詞で書くと、次のような可能性がある。

「家/におくり/ました」→{

(1)「名詞/名詞/名詞」or(2)「名詞/名詞/助動詞」

「家/に/おくり/ました」→{

(3)「名詞/助詞/動詞/名詞」or(4)「名詞/助詞/動詞/助動詞」

4つの品詞列パターンがあるが、この中では (4) の「名詞/助詞/動詞/助動詞」のパターンが最も日本語らしいと言えるのではないだろうか。(3)のパターンも悪くないが(例えば「家/に/

14

送った/人」)、動詞の後に助動詞が来るパターンの方がより日本語らしいと言える*3。また、(1)に関しても、あり得ない訳ではないが(例えば「自然/言語/処理」)、(4)の方がより日本語らしい(と私は思う)。(2)に関しては、名詞の直後に助動詞が来ているため、これは日本語として明らかにおかしい。同様に、各々の単語(表記等)に関しても日本語らしさの観点から評価できる。例えば、「荷送

り」を「におくり」、「真下」を「ました」と平仮名で記述することはめったにないと言える。また、「荷送り」という単語そのものが「送る」や助詞の「に」よりも、はるかに出現する可能性は低い。このように、品詞列と単語そのものの日本語らしさを総合的に評価すれば、より妥当な分割を得

ることができる。これを実現する一つの手法がコスト最小法である。自然な日本語からはずれる単語列を仮定する場合高いコストがかかり、日本語らしい単語列を仮定する場合はコストが低くなるように考える。すなわち、日本語らしい品詞列パターン、よく出現する単語には低いコスト、日本語らしくない品詞列パターン、あまり出現しない単語には高いコストを割り振る。単語分割全体のコストを合計し、最も低いコストになる分割を分割結果とするのが「コスト最小法」である。ここで、任意の数の品詞から成る品詞列パターンをすべて記憶したり、コストを設定することは困難である。このため、実際には、隣り合った2つの品詞間の接続コストを設定し、各品詞間のコストを合計することにより、品詞列パターン全体のコストを計算する。例文「花子を家におくりました。」の単語分割で出現する品詞接続コストを考えると、「名詞/名

詞」や「動詞/名詞」の接続コストよりも、「名詞/助詞」や「動詞/助動詞」の接続コストを少し低く設定する。また、「名詞/助動詞」には非常に高いコストを設定すべきである。これらは上記例文だけでなく、一般的な日本語にもあてはまると思われる。表 2に、品詞接続コスト例を示す。この中で、「名詞+助詞」には ‘5’という低いコスト、「名詞+名詞」には ‘10’という少し高いコストを割り振っている。「名詞/助動詞」はまずありえないので、‘1000’という非常に高いコストを設定している。絶対ありえない接続には無限大のコストを割り振り、可能性の候補として扱わないことにより、計算効率を高めることもできる。しかし、自然言語の常として例外が存在するため、「絶対にありえない」と言い切ることは困難な場合も多い。その場合は、非常に高いコストを設定すればよい。他に妥当な候補がない場合は、高いコストでも選択される余地は残る。単語のコスト例を表 3に示す。単語コストは、ある品詞を仮定した場合のある単語(表記)の出

現のしにくさを表している。品詞を仮定したのは、品詞接続コストと連携してきめ細かい評価を行うためである。「ました」に関して、名詞(真下)と助動詞の可能性があるが、名詞の場合、平仮名表記はまれであるが、助動詞の場合は平仮名表記のみである。品詞を考慮しないと、「ました」に対してどのくらいの単語コストを設定すればよいかがはっきりしなくなる。品詞別にすれば、名詞としての「ました」は高コスト、助動詞としての「ました」には低コストを付与できる。なお、本表では以下の議論を簡単にするため、いくつかの妥当な単語を無視している。例えば、「した」は「勉強した」のようにサ変名詞の語尾、あるいは動詞としても妥当であるが、無視した。

*3 この例では、動詞といっても「おくり」は連用形であり、連用形の後に名詞が続くことはまれである。このように、単なる品詞でなく、その活用形や品詞の細かな分類を行えばより妥当な評価が可能である。

15

表 2 品詞接続コスト例:縦の品詞の後に横の品詞が後続する場合のコスト.

名詞 動詞 助詞 助動詞 句読点

名詞 10 100 5 1000 10動詞 10 10 10 5 5助詞 5 5 5 100 5助動詞 10 10 5 5 5句読点 5 10 1000 1000 1000

表 3 単語コスト例:横の品詞を仮定した場合、縦の単語が出現するコスト. ‘–’は辞書にないことを表す.

名詞 動詞 助詞 助動詞 句読点

花 5 – – – –子 5 – – – –花子 10 – – – –家 5 – – – –下 5 – – – –した 50 – – – –りま 1000 – – – –真下 5 – – – –ました 100 – – 5 –荷送り 20 – – – –におくり 100 – – – –送る – 5 – – –おくる – 10 – – –置く – 5 – – –おく – 5 – – –を – – 2 – –に – – 5 – –。 – – – – 2

16

図 2 例文に対する単語候補の接続可能性とコストを表した単語ネットワーク

以上のコストを仮定し、コスト最小法を用いた 例文「花子を家におくりました。」の単語分割を以下に解説する。ここでは、接続を明示的に表現するために、例文の単語ラティスを等価なネットワークに変換したものを考える(図 2)。この図のなかで、ノードは候補単語、アークは可能な接続を表しており、各アーク、各ノードに付与された数値が、表 2,3から得られたコストである。文頭から文末にいたる一つのパスが単語分割の候補を表現している。単語のネットワーク上で、最も日本語らしいパス、すなわち品詞接続コストと単語コストの総合計を最小とするパスを見つけることがコスト最小法による単語分割である。図 2中で、最小コスト(総コスト 69)のパスが実線で示されている。このパスの分割は、「花子(名詞)/を(助詞)/家(名詞)/に(助詞)/おくり(動詞)/ました(助動詞)/。(句点)」となり、正解である。実際に計算機で最小コストのパスを見つけるには、単語数最小法・文節数最小法と同様にViterbi

アルゴリズムを利用する。単語数最小法に比べて、最小コスト法の Viterbi アルゴリズムは前後の単語品詞に影響を受けるためやや複雑となる (詳しくは授業「知識・自然言語処理」または「自然言語処理」で教えた通り)。本実験では、品詞接続コストと単語コストの両者を考慮する完全なコスト最小法ではなく、実現

が比較的容易な単語コストのみを考えたコスト最小法(以下、単語コスト最小法と呼ぶ)を実現する。単語コスト最小法では、各分割候補中に現れる単語コストの総計が最小となるような候補を解とする。ここで、各単語コストをすべて「1」と仮定すると単語数最小法とまったく等価である。逆に、単語数最小法のアルゴリズムを単語コスト最小法に変更するには、単語数最小法のアルゴリズムにおいて選択した単語ごとに「1」を加えていた箇所を「1」の代わりに単語コストを加えるように変更すれば、単語コスト最小法の高速なアルゴリズムとなる。単語コスト最小法を厳密に記述すると以下のようになる。単語数最小法とほぼ同じである (アン

ダーラインの箇所が単語数最小法との違い)。

問題の定義:単語コスト最小法長さ Lの入力文字列: SL = c1, c2, c3, ..., cL(ci は文字).

17

入力の部分文字列: Sji =入力文字列中の i番めから j番めの部分文字列.

単語 wの表記: str(w) = 単語 wの表記文字列.単語 wの表記の長さ: |w| =単語 wの表記 str(w)の長さ(文字数).

辞書: dic(w) =

{1 if str(w)が辞書の中にある0 otherwise

.

単語コスト: wordcost(wk) =単語 wk の単語コスト単語列: W = w1, w2, ..., w|W|, ここで、dic(wk) = 1.単語列W の長さ: |W| = W 中の単語の数.単語列W の表記: str(W) = W の各単語 wk の表記 str(wk)を接続した文字列.

単語コスト最小法による入力文字列 SL の単語分割:

W = w1, w2, ... = arg minW:str(W)=SL

|W|

∑i=1

wordcost(wi) .

次は、Viterbi アルゴリズムによる上記問題の解法である (単語数最小法と異なる箇所を下線で示す)。単語数最小法とは異なり、(3)終了の時点で N(L)を見ても解 (W)の長さが分からないので、最後の単語から順にバックトラックした後に単語を反転させる操作が必要となる。

Viterbiアルゴリズムによる W の計算(単語コスト最小法)(1) 初期化

N(0) = 0

for i = 1 to L do, N(i) = ∞

(実際には「単語コストの最大値 ×L + 1」を代入しておけばよい)

(2) 繰り返し: x = 1〜L

N(x) = min{w,i|dic(w)=1,Sx

i =str(w)}N(i − 1) + wordcost(w).

W(x) = argw min{w,i|dic(w)=1,str(w)=Sx

i }N(i − 1) + wordcost(w).

B(x) = argi min{w,i|dic(w)=1,str(w)=Sx

i }N(i − 1) + wordcost(w).

(3) 終了

w′1 = W(L).

i(1) = B(L) :w′1 の開始位置.

(4) バックトラック

18

以下を k = 2, 3, ...と、B(k) = 1となるまで繰り返す。

w′k = W(i(k − 1)− 1)

i(k) = B(i(k − 1)− 1)

}k = 2, 3, ...

最後の kを Mとすると、最終的な分割単語列 W は次のように得られる。

W = w1, w2, ..., wM

  ここで wj は次のように定義される。

    w′j = w′

M−j+1

3 日本語文字コード計算機の中ではすべての情報が{0,1}の bitの列で表現されている。文字については、文字と bit

列との対応表を作成し、同じ表を全員が共通に使えば文字の伝達ができる。対応表が文字コード規格であり、日本では JIS、世界的には ISOで規格が定義されている。具体的な日本語処理を行うプログラムを書く場合には、日本語が計算機の中でどのように表現さ

れているか、すなわち、日本語のコード規格を把握しておくことが必須である。本節では日本語コード規格の概略と、課題のプログラムを作成するために必要な日本語符号化方式の一つである日本語 EUC(Extended Unix Code)コードについて解説する。具体的な EUCの処理プログラムについては課題 1において作成する。

3.1 日本語文字コードの概略

日本語の文字コードは多少込み入っている。英語は「アルファベットの大文字・小文字+数字+記号」の数十の文字で表現できるため文字コードは非常に単純であり、ASCIIコードといわれる標準がある。ASCIIコードではすべての文字が 1byte(実は 7bit)で表現されており、計算機処理も楽である。しかし、日本語は、漢字を含めると数千〜数万の文字を含むため、1byte(1〜256)では表現できず 2byte以上の情報が各文字に必要である。この場合、すべての文字を 2byteで表現すると決めればそれほどややこしくはならないのであるが、ASCIIコードの文書も世の中に溢れており、ASCIIコードとの互換性を確保しなければならないところに問題がある。ここで言う互換性とは、ある日本語コードを処理するシステム(例えばエディター)があった場合、入力として ASCIIコードだけで作られた文書を与えても、日本語の文書を与えても、あるいは 2つが混ざった文書を与えても同じように動作する性質のことである。互換性がない場合、ASCIIテキストと日本語の文書をなんらかの付加的な情報で区別する必要が生じ、ユーザに負担を強いる。このため、日本語コードというのは、あくまでも ASCIIコードの拡張であり、ASCIIテキストもその日本語コード体系の一部としなければならない。このため、一般に使われている日本語コードは 1byteの ASCIIコードと日本語用の 2byteのコードが 1つのファイル内に混在することを許す。このため、日本語コー

19

ドはややこしくなる。まずは文字の区別に関係する以下の 4つの言葉を定義する。

字形 文字の具体的な形。実際書かかれた一つ一つの文字。同じ「あ」でも手書きの場合完全にまったく同じ字形では 2度と書けない。

文字 同じ意味や形状を持つとされる個別字形の集合を指す抽象概念字体 文字と同様、個別字形の集合を指す抽象概念であるが、文字より細かい単位。例えば、「学」

は「學」を簡単化した文字であり歴史的には同じ文字であるが、後者を「旧字体」と呼び区別している。旧字体を使う場面もあるからである。文字は同じで字体の異なる字体を「異字体」と呼ぶ。

書体 字形または字形の集まりの装飾的な様式• 明朝体, ゴシック体• セリフ, サンセリフ

やや抽象的で分かりにくいかもしれないが、ようするに「文字」というのは、きれいに書いても、汚く書いても同じ文字は同じであり、また書体が異なっても(丸文字、楷書体等)同じ文字は同じである。そういう意味で、「文字」は「具体的」に定義することは困難であるため、「抽象的」な定義であるということになる。文字コード規格では、この 4つ中で「字体」のレベルで文字を区別する。このため、文字コード

規格における「文字」とは「字体」を指すと考えてよい。実際の文字コード規格は次の 2つに分けることができる。

文字集合 文字の集合を定義したもの. 正確には「符号化文字集合」あるいは「電子化文字集合」と呼ぶ。

符号化方式 文字集合を計算機上で表現する符号 (bitパターン)の定義

文字集合は使用する文字の種類をある範囲に限定するという点が重要である。実際の{0,1}の表現を規定する符号化方式が文字の総数に大きく影響されるからである。たとえば、英語のように「アルファベットの大文字・小文字+数字+記号」の数十の文字ですむ言語では、各文字 1byte(8bit)あれば十分であるが、日本語のように数千〜数万の文字を含む場合は 1byte では表現できないので、1文字を表現する bit長そのものが違ってくる。さらに、日本語用漢字の中のどの漢字を許容するか、その総数で bit長が変化する。計算機処理とは独立に、日本では常用漢字 1945文字が定義されており、新聞等は原則常用漢字しか漢字としてはいない。ただ、あくまでも原則であり、実際の新聞では 5,000種類くらいの文字を使用している。また、さまざまな計算機応用を考えた場合、常用漢字では足りない場面も多い。日本では、JIS(日本工業規格)でいくつかの文字集合が定義されれている。以下の 6つが最も重要であろう。

• ASCII/JISローマ字 (アルファベット+記号+制御文字)• 半角片仮名

20

表 4 3つの日本語符号化方式の特徴

符号化方式 文字集合切り替え方式 特徴 欠点

JISコード 文字集合を切り替えるためのコードを挿入する

各バイト 7bit で表現できる

同じ文字列に対して異なる符号化がありえる

SJIS 最初の1バイトで文字集合の種類が決定される

半角片仮名を 1byteで表現可能

JIS X 0212 を使えない (JIS X 0213 はOK)。文字集合の判別が EUCに比べて少し厄介。

EUC 最初の1バイトで文字集合の種類が決定される

文字集合の判別が容易

半角片仮名が 2byte表現となる

• JIS X 0208 (漢字 6355文字, その他(仮名,アルファベット,記号等)524文字)• JIS X 0212 (補助漢字文字集合 6067文字)• JIS X 0213 (上記の 0208と 0212を包含する最新規格)• JIS X 0221 (ISO 10646の日本版。いわゆる Unicodeを含む規格)

この中で、我々が日常使っている文字は ASCII/JISローマ字と JIS X 0208の一部(第一水準漢字 2965文字のさらに一部)であろう。「半角片仮名」は計算機の記憶能力が低く漢字が表現できなかったころ(片仮名だけでも処理しようとした)の名残りである(が、一部ではいまだ使われている)。最近では、ISO 10646あるいは Unicodeと呼ばれる世界の主要な言語で使用される文字を1つの文字集合で規定しようという試みがあり、急速に普及しつつある。符号化方式は上記の文字集合の1つ、あるいは複数の文字集合を符号化({0,1}列で表現)する

方式である。日本では、以下の 4つが多く使われている。

• JISコード• Shift JISコード(略称 SJIS)• Extended Unix Code (略称 EUC)• UCS (または Unicode) Transfomation Format (略称 UTF. 具体的には UTF-8, UTF-16,

UTF-32の 3種類がある)

最初の 3つの符号化方式は複数の文字集合に対応しているが、最後の UTFは ISO 10647(いわゆる Unicode)専用である。最初の 3つは複数の文字集合をどのようにして切り替えるかが方式の主な違いになっている。特徴を表 4 に示す。 EUC の特徴である文字集合の判別が容易という利点は、日本語を処理するプログラムが書きやすいことを意味しており、この利点によって EUCはプ

21

ログラムの日本語テキストの内部表現として利用されることが多い。最終的に JISや SJISの符号化方式を扱わなければならない場合も、入出力の時点で EUCに変換し、内部では EUCを用いている場合も多い。本実験でも、EUCを用いることとする。EUCを使って課題 2以降を行うための基本的な事項を課題 1によって把握してもらう。EUCの詳細、または日本語コードに関する包括的な解説は、最後の章で挙げた Ken Lundeまたは矢野啓介の本を参照のこと。

3.1.1 EUCEUCはもともと日本語の文字だけのための符号化方式ではない。言語を問わず、複数の文字集

合を符号化するために開発された枠組みである。さらに、文字集合を切り替えるために複数の方式を含んでいるため、EUCの仕様全体はかなり大きなものである。全体の話は本実験の範囲を越えるので、本実験に関係する部分のみに限り以下に解説する。EUCのいくつかの符号化方式のなかで、日本語に対して主に用いられるのは「EUC圧縮フォー

マット」と呼ばれるものである。このフォーマットでは、日本語の標準的な文字集合の4つをすべて表現できる。また、このフォーマットは可変長の符号であり、各文字集合中の文字を次のようなバイト数で表現する。

ASCII/JISローマ字: 1byte半角片仮名: 2byteJIS X 0208 2byteJIS X 0212 3byte

しかし、半角片仮名と JIS X 0212 の文字が使われることはまれなので、本実験では ASCII/JISローマ字と JIS X 0208 の文字集合に限ることとする。この2つの文字集合に限ると、EUC 圧縮フォーマットでは、各文字は 1byte か 2byte かのどちらかで表現されており、1byte の場合はASCII/JISローマ字、2byteの場合は JIS X 0208の文字を表していることになる。テキストを計算機処理する場合、テキストの先頭から 1byteづつ処理することが基本であるが、

EUC圧縮フォーマットでは1つの文字が可変長 byteで表現されるため、1文字に相当する符号の切れ目を認識することが最初に必要となる。先頭、あるいはある文字符号の最後を認識した直後の1byteは、次の2通りのいずれかである。

• 1byte文字• 2byte文字の 1byte目の符号

EUC圧縮フォーマットでは、1byteの数値を符号なしの 8bit整数と見なした場合、次のようにして判別できる。

• 1byteの値が 127以下 (すなわち先頭 bitが 0)の場合:1byte文字• 1byteの値が 128以上 (すなわち先頭 bitが 1)の場合:2byte文字の 1byte目

すなわち、先頭 bitが 0であるか 1であるかによって判別できる。先頭 bitが 1である場合は、次

22

表 5 文字種による EUC圧縮フォーマットのコード範囲 (16進数)

文字種 1byte目 2byte目

記号 a1 or a2 a1-fe数字 a3 bo-b9

アルファベット a3 c1-fa平仮名 a4 a1-f3片仮名 a5 a1-f6

ギリシャ文字 a6 a1-d8キリル文字 a7 a1-f1罫線 a8 a1-c0漢字 b0-f4 a1-fe

表 6 EUC圧縮フォーマットの記号に対するコード (16進数)

記号 1byte目 2byte目

スペース a1 a1、 a1 a2。 a1 a3, a1 a4. a1 a5? a1 a9! a1 aaー a1 bc

の 1byteを含む 2byteで JIS X 0208文字集合中の1文字を表す。以上の条件を満たすために、EUC圧縮フォーマットでは JIS X 0208の文字は 2byteで各 byte

共に 128 以上となるように設計されている。また、ASCII コードほ 127 以下である。すなわち、全体を見渡したとき、127以下の byteはすべて 1byteの ASCII/JISローマ字1つを表しており、128以上の byteは前後のいずれかの 1byteと組み合わさって 2byteの文字を表現する。JIS X 0208文字集合中の文字の種類による各 byteの数値範囲を表 5に示す。また、重要な記号

については、具体的な数値を表 6に示す。例えば、各バイトが次のような値のシーケンスはその下に書いてあるような文字に対応する。1

行目が 16進数で、2行目が 10進数、3行目が各部分に対応する文字である。

23

16進 a4 b3 a4 ec a4 cf 45 55 43 c9 e4 b9 e610進 164 179 164 236 164 207 69 85 67 201 228 185 230

文字列 こ れ は E U C 符 号

4 課題本実験では、日本語テキストを入力し、単語分割を行うシステムを複数構築する。前節ではかな

りたくさんの手法を説明したが、作成するのは以下の方法のみでよい。

• 字種による分割• 最長一致法• 単語コスト最小法

課題は 5つに別れており、各課題の概要は以下である。

課題1 日本語文字コード (EUC): まずは、日本語のテキストが計算機内でどのように表現されいるかを学ぶ。特に、最も計算機プログラムが書きやすいと言われる EUCコードの処理方法を学習する。

課題2 字種による分割 EUC コードの知識を利用して、簡単な日本語分割システムを作成する。さらに、日本語単語から英単語に変換する簡単なプログラムを与えるので、それを利用して簡単な日英辞書引きソフトを作成する。

課題3 最長一致法 辞書を用いた単語分割システムを作成し、課題2で作成した辞書引きソフトを改良する。辞書を読み込んで、単語を引くプログラムの作成が中心である。辞書の内容は与える。

課題4 単語コスト最小法 Viterbiアルゴリズムを用いた、単語コスト最小法による単語分割システムを作成する。

課題5 高速化 課題4で作成した形態素解析システムの辞書のデータ構造を改良することにより高速化する。データ構造は何を用いてもよい。(最終的に長めのテキストで他の学生と速度比較 (競争)を行う)

4.1 課題 1: 日本語文字コード:EUC

課題1は、日本語のテキストを文字に分割し、各文字の種類を出力するプログラムを書くことでEUCコードに慣れる*4。

*4 多少難易度が上がるがUTF-8などのUnicodeで実験を進めることも可能である。UTF-8で実験を進めたい場合は担当教員に相談してください。

24

4.1.1 課題 1-1: 文字切り出しプログラムの理解入力テキストを標準入力から読み込み、文字に分割し、1行に1文字を標準出力に出力するプロ

グラムを解説する。改行文字は出力しないようにしている。例えば、次のような入力:� �このコードは CREUC符号。� �

に対して、次のような出力を出すようにすればよい。 CR は改行文字であるので無視される。� �このコードはEUC符号。� �

手始めに、標準入力から読み込んだテキストを 1byteごとにその値の 10進と 16進の数値を出力するプログラムを示す*5。いろいろなテキストの実際の数値を見てみると EUCコードの実際がよく分かるかもしれない。各バイトの数値を表示するプログラム� �

#include <stdio.h>

main(){

int c;

while ((c = getchar()) != EOF) {

printf("%5d %5x\n", c, c);

}

}� �*5 プログラムはここ! /home/prof/myama/jikken/nlplab/src/dechex.c

25

この例では、各バイトは getchar() で読み込まれる。この際注意するのは、getchar() の返り値は int 型である点である。char 型がデフォルトで signed である機種 (Mac の unix であるDarwin等)では、char型は-128〜+127の値しか表現できない。このため、getchar()の返り値を char型に入れると、128以上の値が負の値と解釈される (先頭 bitが 1であるため) *6。

[以下、横線に挟まれた部分は、非常に細かい話なので、興味がなければ飛ばしてよい。]明示的に unsigned char型を使えば、表現できる範囲は 0〜+255までとなるので getchar()

の返り値を代入しても int型に代入したときと同じ結果が得られる (0以上の値)。いずれにせよ、代入されるビット列としては unsigned charでも singed charでも同じである。ただ、型が異なるとその同じビット列を数値として解釈する場合に違いが生じるのである。文字列として見た場合はどちらでも同じであり、特に問題は生じない。この様子をよく理解するためには、以下のプログラムに EUC のテキストを入力するとよい。

getchar()が読み込んだ値の解釈の違いが分かるであろう。変数の型の違いに解釈の違いを表示するプログラム� �#include <stdio.h>

main(){

char c;

int ic;

unsigned char uc;

while ((ic = getchar()) != EOF) {

c = ic;

uc = ic;

printf("int:%3d, char:%3d, unsigned_char:%3d\n", ic, c, uc);

}

}� �繰り返すが、この違いは{0,1}パターンの違いによるものではない。すべての型で (int型は最後の1byte)内容は同じであるが、数値としての解釈が異なるだけである。

課題 1-1のプログラム例を以下に示す*7。getchar()で読み込んだ各 byteを putchar(c)でどんどん出力していきながら、必要なところにリターンコード'\n'を挿入する方法もあるが、今回は以後の課題への応用も考えて、一旦 char型の配列上で、1文字からなる文字列を構成してから出力する方法をとった。

*6 ただし、char型のデフォルトが unsignedであるようなOS(IRIX等)では、char型が 0〜+255の値を格納でき、getchar()の返り値を char型の変数に代入しても同じ結果になる。自宅の計算機で本実験を行う場合は、char型がデフォルトで signedなのか unsignedなのかをチェックした方がよい。

*7 プログラムはここ! /home/prof/myama/jikken/nlplab/src/chseg.c

26

EUC圧縮フォーマットテキストの文字を切り出すプログラム� �#include <stdio.h>

#include <stdlib.h>

main(){

int c;

char euc_ch[3];

while ((c = getchar()) != EOF) {

if(c >= 128) {

euc_ch[0] = c;

if((c = getchar()) != EOF){

euc_ch[1] = c;

euc_ch[2] = '\0'; /* C言語における文字列の終端を表す文字 */

} else {

fprintf(stderr, "Input text isn't encoded in EUC code.\n");

exit(2);

}

} else if(c == '\n') {

continue;

} else {

euc_ch[0] = c;

euc_ch[1] = '\0';

}

printf("%s\n", euc_ch);

}

}� �このプログラムを十分理解することが、課題 1-1である。最後に入力テキストが EUCコードになっているかどうか分からないときに EUCコードのテキ

ストに変換するコマンド nkfの使い方の例を示す。� � 未知の符号化方式のファイル textを EUCコードのテキスト text.eucへ変換:

% nkf -e < text > text.euc

 未知の符号化方式のファイル textを上記で作成したプログラムに入力する:

% nkf -e < text | command� �

27

4.1.2 課題 1-2: 文字種判別プログラムの作成文字に区切るプログラムを拡張し、各文字に文字の種類を付与するプログラムを書け。文字種と

しては、以下の 9種類を識別せよ。の中は出力するべき文字種の記号である。

• ASCII文字(数字、アルファベット、記号を含む 1byte文字)• 平仮名• 片仮名• 横棒(‘ー’)• 数字• 2byteコードとしてのアルファベット• 漢字• 句読点(‘。’, ‘、’, ‘! ’, ‘? ’の4種)• その他

前節の入力「このコードは EUC符号。」に対しては、次のような出力となるようにせよ。� �こ 平仮名の 平仮名コ 片仮名ー 横棒ド 片仮名は 平仮名E ASCIIU ASCIIC ASCII符 漢字号 漢字。 句読点� �

各文字・文字種の数値・数値の範囲は表 5,6 (23ページ)を参考にせよ。なお、例文は以下のところにたくさんあるので、テストに使用してよい。1行目が EUCのファ

イル。2行目は UTF-8で符号化されているファイルである。

/home/prof/myama/jikken/nlplab/sentences-euc/home/prof/myama/jikken/nlplab/sentences-utf8

1文/ 1ファイルとなっている。もちろん、自分で作成したメール等の文章も使ってみるとよい。

28

4.2 課題 2: 字種による単語分割

本課題では、字種が変化するところで分割する最も単純な分割プログラムを作成し、日英辞書引きコマンドを通して、第1バージョンの自動日英辞書引きシステムを作成する。

4.2.1 課題 2-1: 字種による単語分割プログラムの作成課題 1-2で作成した文字切り出し・字種付与プログラムを改造して字種が変化するところを単語

境界と仮定する単語分割プログラムを作成せよ。字種としては、課題 1-2で用いた 9種類を用いれば十分であるが、自分で工夫してより細かい字種を判別するようにしてもよい。横棒 ‘ー’は片仮名の一部とした方がよいことに注意せよ。例えば、

サッカー、サーキット、エルニーニョ、サンドペーパー、...

のように、片仮名の名詞の中に横棒はよく現れる。この他、平仮名列の中にも現れることがあるので(例えば、「えーと」等)、考慮した方がよいかもしれない。結果を見て、簡単に回避できる誤りがあれば、プログラムを改良するとよいだろう。入出力は課題 1と同様、標準入出力とする。出力は、分割された単語を1行ごとに改行されてい

ること。例えば、入力「このコードは EUC符号。」に対しては、次のような出力となるようにせよ。� �このコードはEUC符号。� �

4.2.2 課題 2-2: 日英自動辞書引きシステム version 1各行の文字列を単語とみなして日英辞書を引き、その結果を出力するコマンド ‘jedic’を使用で

きるようにするために、以下のディレクトリをコマンド・パスに追加せよ。

/home/prof/myama/jikken/nlplab/bin

課題 2-1で作成した分割プログラムとパイプで接続することにより、以下のような出力が得られる。課題 2-1 で作成したプログラムが ckseg という名前で、ファイル text.txt に日本語テキスト「このコードは EUC符号。」が入っているものとする。

29

� �% nkf -e text.txt | ckseg | jedic

このコード /code/cord/chord/はEUC符号 /sign/mark/symbol/。� �

このように、jedicコマンドは、もとの日本語と英語をペアで各行に表示するが、辞書にない単語には英語を出力しないようになっている。jedicが引く単語のリストは、以下の場所にある。

/home/prof/myama/jikken/nlplab/dic/jedic.txt

この辞書は、James Willian Breen(オーストラリア)が中心になって活動しているEDICTプロジェクトの成果であり、フリーで公開されている*8 。2000年 1月現在のエントリー数 (Ver.V00-001)は、68,264単語(日本語)である。作成されたプログラムを shell scriptでまとめて1つのコマンドとして利用できるようにした方

がテストが楽である。このコマンドを用いて、様々なテキストの辞書引きを行い、問題点を把握せよ。特に、動詞については字種による分割ではほとんどうまくいかないと予想されるが、実際はどうか?

4.3 課題 3: 最長一致法

課題 3 では、課題 2 の単語分割プログラムを最長一致法による分割プログラムに変更し、辞書引き性能を改善する。本格的な日本語の単語辞書を使うことによって、以下のような改善が見込まれる。

• 長い漢字だけの名詞をより短い単語に分割できるため、日英辞書のエントリーにある可能性が高まる。例えば、「自然言語処理」は全体では辞書に掲載されている可能性は低いが、「自然|言語|処理」と分割できれば、それぞれの単語は辞書のエントリーとして存在する可能性が高まる。

• 動詞を基本形にもどすことにより、動詞に対する辞書引き性能を向上できる。

4.3.1 課題 3-1: 日本語辞書引きプログラムの作成以下のファイルは日本語の辞書として用意したものである。

*8 http://www.dgs.monash.edu.au/~jwb/edict.html

30

/home/prof/myama/jikken/nlplab/dic/jdic.txt

この辞書を用いて、日本語テキストに現れる表記から、「読み、品詞、基本形」のの情報を返す関数を作成せよ。jdic.txtの内容は以下のようになっている。� �これ コレ これ 名詞-代名詞-一般7.05215符号 フゴー 符号 名詞-一般 14.0819家 イエ/ウチ 家 名詞-一般 7.88928送り オクリ 送る 動詞-自立 10.7799は ワ は 助詞-係助詞3.56106。 。 。 記号-句点 3.27649� �

左から、「表記、読み、基本形、品詞、単語コスト」の順序である。各カラムはタブ ('\t')で区切られている。品詞中の ‘-’の後に記述してあるものは、品詞の細分類と呼ばれるもので、コスト最小法で細かな接続コストを設定するときに用いられる。本課題では、品詞は単なる文字列と見なして、そのまま出力すればよい。また、残念ながら、この辞書には ASCII文字の単語が登録されていないので、入力に ASCIIコード文字が入っていると単語が見つからない。入力には ASCIIコードの文字が入っていないと仮定してよい。辞書を計算機上で実現するためにはさまざまな方法が考えられるが、課題 3-1では、線形探索を

用いたプログラム (プログラム例を与えるができるだけ見ない方がよい)と二分探索を用いたプログラムの 2種類を実現せよ (次の課題 3-2で、探索方法による実行時間の違いを測定する)。

4.3.2 課題 3-2: 最長一致法による単語分割プログラムの作成課題 3-1で作成した関数を用いて、最長一致法の単語分割プログラムを作成せよ。出力は分割さ

れた単語に対応する辞書の情報をすべて出力せよ。すなわち、「表記、読み、基本形、品詞」を各単語に関して出力する。例えば、「これは符号。」に対して、次のような出力が期待される。� �これ コレ これ 名詞-代名詞-一般は ワ は 助詞-係助詞符号 フゴー 符号 名詞-一般。 。 。 記号-句点� �実現において問題となるのは、ある文字位置まで分割が進んだときに、日本語辞書の中に後続す

る単語が一つも見つけられない場合である。2つの対処法がある。

1. 1文字スキップする。後続する1文字を単語と見なして、出力し、その先を進める。2. 前の単語分割が誤りであったと考え、1つ前の単語分割を取り消す。全体をうまく分割できるまで、この取り消しを再帰的に行う。これは、人工知能の分野でバックトラックと呼ばれ

31

る手法に相当する。これを実現するには、1単語の分割を1つの C言語の関数として実現し、この関数の再帰的な呼び出しによって全体を分割するように作れば、簡単に作成できる。

ここでは、(1)の1文字スキップする実現で十分である。単語コスト最小法による課題 4のプログラムは (2)の方法を包含するためである。さらに、課題 3-1で作成した 2つの辞書引き関数 (線形探索と二分探索)で、どの程度実行速度

が異なるか比較せよ。

4.3.3 課題 3-3: 日英自動辞書引きシステム version 2課題 3-2で作成した単語分割プログラムを用いて、辞書引きシステム ver.2を作成せよ。jedicコ

マンドは、オプション ‘-n’(ここで nは数値)を取り、入力行の n番めの文字列を辞書に探しに行く。「表記、読み、基本形、品詞」の順で出力されている場合、「基本形」で辞書引きするのがよいので、この場合、‘-3’というオプションを付ける。デフォルトは ‘-1’である。辞書引き結果を観察し、字種による分割による方法から改善された点をまとめよ。

4.4 課題 4: 単語コスト最小法

4.4.1 課題 4-1: 単語コスト最小法による単語分割プログラムの作成単語コスト最小法による単語分割プログラムを作成せよ。単語コストとしては、与えた辞書の中

にある値 (右端の数値)を用いよ。2.5節で述べた Viterbiアルゴリズムを使用せよ。

4.4.2 課題 4-2: 日英自動辞書引きシステム version 3課題 4-1で作成した単語分割プログラムを用いて、辞書引きシステム ver.3を作成せよ。辞書引

き結果を観察し、性能を評価せよ。

4.5 課題 5: 高速化

単語コスト最小法に基づくシステムの辞書データ構造を改良して高速化せよ(辞書引きシステムの実験はしなくてよい)。辞書のデータ構造としては何を用いてもよい。課題 4のシステムとある程度長いテキストを用いて、処理速度を比較せよ。処理速度を理論的に解析してレポートに書くと評価が高くなる。また、同一の長めのテキストを用いて、他の人と処理速度の比較をする予定である。データ構造としては、2年生の授業「データ構造とアルゴリズム」および実習や 3 年生の授業

「知識・自然言語処理」あるいは「自然言語処理」で習得したデータ探索手法を使うとよいだろう。例えば、「ハッシュ法」,「トライ」, 「パトリシア木」は、いずれも辞書の実現に使用できる(が、二分探索より早くなるかどうかはやってみないと分からない)。

32

5 文献案内以下に、本実験および自然言語処理に関する理解を深めるための参考文献を挙げる。自然言語処

理に関してはたくさんの本があるが、カテゴリーごとに代表的と思うものを日本語と英語の本をそれぞれ一冊ずつ挙げた。

自然言語処理一般について:以下の本が代表的な入門書である(形態素解析を含む)。

長尾真編. 1996. 「自然言語処理」, 岩波書店.

C.D.Manning and H. Schutze. 1999. “Foundations of Statistical Natural LanguageProcessing.”

日本語文字コードに関して以下の本が包括的である。

矢野啓介. 2010. 「プログラマのための文字コード技術入門」, 技術評論社.

Ken Lunde. 2008. “CJKV Information Processing, 2nd Ed.,” O’Reilly & Associates,Inc.

日本語および品詞体系について:

益岡隆志, 田窪行則. 1992.「基礎日本語文法」, くろしお出版.

Masayoshi Shibatani. 1990. “The Language of Japan,” Cambridge University Press.

辞書構造とデータ探索を含むデータ構造とアルゴリズムの入門書:

A.V.エイホ, J.E.ホップクロフト, J.D.ウルマン. 1987. 「データ構造とアルゴリズム」,培風館.

T.H.Cormen, C.E.Leiserson and R.L.Rivest. 2009. “Introduction to Algorithms, 3rdEd.,” MIT Press.

33

Recommended