見出し画像

オープンソースの中国語辞書を使ってMeCab用中国語辞書を作る

自然言語処理の基本的な入力データは単語です。英語は単語境界がスペースなので処理が簡単です。しかし日本語や中国語などの言語は単語境界が曖昧ですので、まずはテキストを分割するステップが重要になります。日本語の場合は幸いにも優れた辞書が多数ありますが、中国語の場合はそうでもないようです。

ここでは、オープンソースの中国語辞書(CC-CEDICT)をベースに中国語向けMeCab辞書を作りました。ただしこの辞書は文法的知識に基づかない、コストを機械学習(CRF)で学習していない辞書になります。

辞書の変換

まずはCEDICTをスクリプトでCSVファイルに変換します。例えば次のようなスクリプトを書きます。

import re

pattern = re.compile(r"^(.*?) (.*?) \[(.*?)\] /(.*?)$")

# surface -> csv (surface, left id, right id, cost, pinyin, traditional, simplified, definition)
dict = {}

with open("cedict_ts.u8") as f:
   for line in f:
       line = line.strip()
       if line.startswith("#"):
           continue

       match = pattern.match(line)
       if match:
           traditional = match.group(1)
           simplified = match.group(2)
           pinyin = match.group(3)
           definition = match.group(4)

           cost = int(max(-36000, -400 * (len(traditional) ** 1.5)))
           dict[traditional] = f"{traditional},0,0,{cost},*,*,*,*,{pinyin},{traditional},{simplified},{definition}"
           dict[simplified] = f"{simplified},0,0,{cost},*,*,*,*,{pinyin},{traditional},{simplified},{definition}"

with open("cedict.csv", mode='w') as f:
   for value in dict.values():
       f.write(value + "\n")

CEDICTの1エントリは

1. 繁体字
2. 簡体字
3. ピンイン(発音)
4. 意味

が含まれています。中国語には様々な意見がありますが、私は繁体字も簡体字も中国語であると考えていますので両方の入力を受けられるようにします。CEDICTの情報をもとに同じ行に対して繁体字と簡体字のエントリを作ります。

コストの推定は「MeCab の辞書構造と汎用テキスト変換ツールとしての利用」にある式で計算します。これは単語長の1.5乗に負の数を乗じてコストを得ます。

設定ファイル

ここではコスト推定に文法知識は使いません。またCEDICTには品詞などの文法に関する情報が含まれません。したがってここで作成するMeCab辞書は文法を知らない辞書になります。matrix.defは最小構成の

1 1
0 0 0

です。

文法情報のある辞書の場合はCSVファイルの2列目、3列目に品詞IDが入ります。2列目は左から見た場合の品詞で、3列目は右から見た場合の品詞です。多くの場合はどちらも同じIDが入りますが、言語によっては別のIDを割り当てることもできます。

matrix.defには品詞ID同士の接続コストを設定できます。例えば「行か ない」は正しい日本語ですが「行く ない」は正しくないため、この接続に高いコストを与えることで文法知識を辞書に与えます。

char.defはUnicodeに対して字種情報を与えます。中国語は主に漢字で構成されるので、漢字の範囲にCHINESEなどの情報を設定すればよいでしょう。

また字種ごとに未知語解析の設定ができます。日本語の場合はたとえその語を知らなくても字種が単語境界になることがしばしばあります。例えばニューラルネットワークという単語が辞書にないときに「ディープラーニングの基礎であるニューラルネットワークを中心に解説する」という文章を見た場合にひらがなの「である」に続いてカタカナの「ニューラルネットワーク」があり、その後にひらがなの「は」が続くため、ここまでが未知語であると推定しても誤りとは言いにくいと思います。しかしひらがなは「基礎」と「ニューラルネットワーク」に挟まれた「である」は1単語なのかは議論が分かれるところでしょう。

unk.defは未知語の品詞とコストを設定できます。この辞書は文法情報がないので全ての字種について単一のコストを設定しています。

DEFAULT,0,0,-3200,*,*,*,*,*,*
SPACE,0,0,-3200,*,*,*,*,*,*
CHINESE,0,0,-3200,*,*,*,*,*,*
SYMBOL,0,0,-3200,*,*,*,*,*,*
NUMERIC,0,0,-3200,*,*,*,*,*,*
ALPHA,0,0,-3200,*,*,*,*,*,*
HIRAGANA,0,0,-3200,*,*,*,*,*,*
KATAKANA,0,0,-3200,*,*,*,*,*,*
CHINESENUMERIC,0,0,-3200,*,*,*,*,*,*
GREEK,0,0,-3200,*,*,*,*,*,*
CYRILLIC,0,0,-3200,*,*,*,*,*,*

-3200は4文字の単語のコストです。品詞情報はありません。先程のカタカナの例ならば未知のカタカナは名詞である可能性が高ければ、名詞についての行を作成して適切なコストを設定します。

dicrcは辞書の設定ファイルです。

; List of features
; f[0]:  pos1
; f[1]:  pos2
; f[2]:  pos3
; f[3]:  pos4
; f[4]:  pinyin pronunciation
; f[5]:  traditional Chinese character form
; f[6]:  simplified Chinese character form
; f[7]:  definition

cost-factor = 700
bos-feature = BOS/EOS,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*

; If the analysis target is a known word, eval-size specifies criteria for correct answers.
; Unlike Japanese, Chinese has no conjugation.
; Therefore, four elements that are pos 1, 2, 3, 4 are evaluated. Other elements, such as pronunciation information, are ignored.
eval-size = 4
unk-eval-size = 4
config-charset = utf8

output-format-type = cedict

node-format-cedict = %m\t%f[0],%f[1],%f[2],%f[3],%f[4],%f[5],%f[6],%f[7]\n
unk-format-cedict = %m\t%f[0],%f[1],%f[2],%f[3],%f[4],%f[5]\n
bos-format-cedict =
eos-format-cedict = EOS\n

node-format-traditional = %f[5] 
unk-format-traditional = %f[5] 
bos-format-traditional =
eos-format-traditional = \n

node-format-simplified = %f[6] 
unk-format-simplified = %f[6] 
bos-format-simplified =
eos-format-simplified = \n

ここでは簡体字と繁体字の変換を入れたかったため、その情報を追加しています。

辞書のビルド

すべてのファイルが揃ったら辞書をビルドします。

[mecab-cedict]# /usr/local/Cellar/mecab/0.996/libexec/mecab/mecab-dict-index -f utf-8 -t utf-8

./pos-id.def is not found. minimum setting is used
reading ./unk.def ... 11
emitting double-array: 100% |###########################################|
./model.def is not found. skipped.
./pos-id.def is not found. minimum setting is used
reading ./cedict.csv ... 187741
emitting double-array: 100% |###########################################|
reading ./matrix.def ... 1x1

done!

mecab-dict-indexへのパスは自身の環境に合わせて変更してください。

中国語のニュースサイトから適当な1文を探して実行してみます。

[mecab-cedict]# mecab -d .
武汉市解除离汉离鄂通道管控措施
武汉市	,,,,Wu3 han4 shi4,武漢市,武汉市,Wuhan city on Changjiang
解除	,,,,jie3 chu2,解除,解除,to remove/to sack/to get rid of/to relieve (sb of their duties)/to free/to lift (an embargo)/to rescind (an agreement)/
离	,,,,li2,離,离,to leave/to part from/to be away from/(in giving distances) from/without (sth)/independent of/one of the Eight Trigrams 八卦[ba1 gua4]
汉	,,,,han4,漢,汉,man/
离	,,,,li2,離,离,to leave/to part from/to be away from/(in giving distances) from/without (sth)/independent of/one of the Eight Trigrams 八卦[ba1 gua4]
鄂	,,,,E4,鄂,鄂,abbr. for Hubei Province 湖北省[Hu2 bei3 Sheng3] in central China/surname E/
通道	,,,,tong1 dao4,通道,通道,(communications) channel/thoroughfare/passage/
管控	,,,,guan3 kong4,管控,管控,to control/
措施	,,,,cuo4 shi1,措施,措施,measure/step/CL:個|个[ge4]/
EOS

必ずしも文法的に適切かはわかりませんが、一応単語に分割することができます。この入力文は簡体字中国語ですので、これを繁体字に変換してみます、

[mecab-cedict]# mecab -d . -Otraditional
武汉市解除离汉离鄂通道管控措施
武漢市 解除 離 漢 離 鄂 通道 管控 措施

逆に繁体字のニュースサイトから例文を探してきて分割と簡体字への変換をします。

[mecab-cedict]# mecab -d .
近期自煮防疫已成了最新飲食觀
近期	,,,,jin4 qi1,近期,近期,near in time/in the near future/very soon/recent/
自	,,,,zi4,自,自,self/oneself/from/since/naturally/surely/
煮	,,,,zhu3,煮,煮,to cook/to boil/
防疫	,,,,fang2 yi4,防疫,防疫,disease prevention/protection against epidemic/
已	,,,,yi3,已,已,already/to stop/then/afterwards/
成了	,,,,cheng2 le5,成了,成了,to be done/to be ready/that's enough!/that will do!/
最新	,,,,zui4 xin1,最新,最新,latest/newest/
飲食	,,,,yin3 shi2,飲食,饮食,food and drink/diet/
觀	,,,,guan4,觀,观,Taoist monastery/palace gate watchtower/platform/
EOS

[mecab-cedict]# mecab -d . -Osimplified
近期自煮防疫已成了最新飲食觀
近期 自 煮 防疫 已 成了 最新 饮食 观

課題

繰り返しになりますが、この辞書はまったく文法要素を考慮していません。せっかくMeCabを使っているのに、基本的には長い単語を優先して拾っているだけという原始的なテキスト分割しか実現していません。

もし文法知識を辞書に入れる場合には次のような作業が必要になります。

まずCEDICTの単語に品詞情報を入れます。今回の辞書は4階層の品詞を入れることができるようにしてありますが、実際には空欄( "*" )です。ここに適切な品詞を設定します。例えば名詞とか動詞とかです。さらに階層で品詞情報を与えられるので「名詞」→「固有名詞」→「人名」→「姓」のような4つの情報を与えられます。

ここで問題があるのは品詞情報をどのように設計するかです。日本語や中国語の場合は「山田太郎」のように姓→名の順に繋がりますので「名詞・固有名詞・人名・姓」には「「名詞・固有名詞・人名・名」が繋がりやすい(低いコストが割り当てられる)ように学習するのが理想です。しかし「ドナルドトランプ」の場合は「ドナルド」が「名」で「トランプ」は「姓」ですからアメリカ人などの姓名は別の品詞にしたほうがきれいに辞書を設計できるかも知れません。

「私は日本人です」は「我是日本人」ですが「私は疲れた」は「我很累」です。日本語だと「は」が入りますが中国語では形容詞をつなげる場合には「是」が含まれません。「累」は「疲れた」ですが、単独で使うことはなく、何もつけない場合は「很」を前に置きます。

こうしたことを、うまくMeCabの辞書に合わせて入れることが重要になります。理想的には言語の専門家と話し合って必要な品詞を洗い出すとよいでしょう。私は細かい中国語文法を理解していません。

単語の長さも議論の対象になるでしょう。「日本人」を1単語にするか「日本 人」と2単語に分けるかです。CEDICTはかなり長い単語が含まれます。例えば「2019冠状病毒病」を1単語とするのは個人的にはかなり抵抗があります。しかしスクリプトが出力したCEDICTはおよそ19万語入っているため、これを洗い直すのは非常に手間がかかるので棚上げしています。

一般に単語長が短いほうが辞書のサイズは小さくできます。「日本」「日本人」「中国」「中国人」を1単語とした長単位の辞書よりも「日本」「人」「中国」のほうが少ない単語で同じ表現をカバーできます。

結局のところ、単語長をどうするかはテキスト分割の目的によります。もしSiriやGoogleアシスタントのような音声データを使う場合は長いほうがうまくいくケースが多いと思います。例えば群馬県には「上泉(かみいずみ)駅」という駅があります。そして東京には「神泉(しんせん)駅」という駅があります。また人名で「神泉(かみいずみ)さん」という人もいます。

もし単語長が短く「上泉」「駅」や「神泉」「駅」のように分割する辞書を設計して、その上で音声認識AIに応用したとしましょう。その場合は「かみいずみえき周辺のレストランを探して」と発話した場合に「神泉駅周辺のレストランを探して」が現れる可能性があります。例えばSiriだと現在(2020年4月9日)の時点ではそうなっています。こうしたことを問題にするのであれば「上泉駅」や「神泉駅」という単位で単語を持っておいて、それらに発音を与えると改善につながるかも知れません。

文字列分割に完璧な分割はありません。適切ではない分割はあると思いますが、適切な分割は用途によってかわります。このことを言語の専門家を交えて設計することが重要だと思います。

その後に、タグ付き分割データを作ります。作業量が多いので複数人でやる必要があるかも知れません。そのときに作業する人によって基準がかわらないように、きちんとしたマニュアルや、相談できるマネージャーのような役割の人が重要になります。その他、効率的に作業できるようなソフトウェアを作る必要があるかも知れません。

このことが良質な中国語の単語分割辞書がなかなか現れない理由の一つになっていると思います。

コラム

以前、少し時間を費やして中国語のテキスト分割についてのツールを調べたことがあります。もちろんすべてのツールを確認したわけではないと思いますが、概ね中国語の分割ツールはあまりよくありません。

まず技術面で遅れているものが多いと思います。ただの最長一致法(この辞書もそうですが)を用いているだけのものとか、辞書の中身を見ると品詞情報も何もないコストだけ(この辞書もそうですが)だったりします。日本語のMeCab + unidicに比肩するツール(辞書)は見つけることができませんでした。

品質面でもいまいちでした。含まれている単語にまるで一貫性がなかったり、単語境界が明確に間違っているものが大量に含まれていたりします。The Stanford Word Segmenterはスタンフォード大学が手掛けているため(学習データは北京大学とかのもの)高品質だと信じられているケースもあると思います(一緒に仕事をした人はそう思っていた)。しかし、辞書を見てみると高品位とは言えないものでした。

テキスト分割の研究は主に日本でなされてきたと思います。中国語などでもテキスト分割は重要であるのですが、おそらく経済発展が近年であることなどの事情もあって研究があまり進んでいないように見えます。さらに日本の研究は日本語で書かれていることが多いのも、テキスト分割の知見が世界に共有されにくい一因でしょうか。

MeCabは優れたツールですが20年近く前の研究です。現代ではテキスト分割も新しい手法が登場しています。例えばニューラルネットワークで言語モデルを作ってそれに基づく分割です。

(詳しく理解しているわけではありませんが、文法情報がない単なる分割済みテキストをRNNで言語モデルを作り、言語モデルは与えた単語列に確率を割り振るので正しい(学習データに近い)分割に高い確率が与えられるというものだと思います。このような言語モデルベースの分割では単語情報が要らないのかも知れません。そうすると学習データ作成は楽になると思います。しかしjuman++はMeCabより遥かに低速です)

(sentencepieceのような教師なし学習ではテキストを渡すだけで学習ができます。しかし文法に基づかない出現頻度に依存した分割結果になるので、sentencepieceが向かない分野もあるでしょう。特に日本語の音声情報を扱う用途では厳しいのではないでしょうか。例えば「竹刀」は「し」「ない」でも「しな」「い」でもないので、ここを分割してしまうと音声情報が壊れてしまいます。中国語の場合は割とうまくいきそうな予感はあります)

もしかすると、今からMeCab向けに頑張って中国語の注釈(品詞情報など)付き学習データを作っても割に合わないのかも知れませんが、中国語の需要はとても大きく、またテキスト分割の知見は日本人が優位性を持っているので、やりがいのあるテーマかも知れないと思っています。

単語分割が重要な言語

他の言語の知識があるわけではないので、伝聞や憶測を含みます。

韓国語は日本語で言うところの文節でスペースを入れる習慣があるそうです。ですから、ある程度はテキスト分割されていますが、より細かい単位に分割するにはテキスト分割ツールが重要になりそうです。

トルコ語はスペースで分割されますが、接尾辞などが付属します。例えば「私は働いています」はçalışıyorumと書きますが、動詞の部分はçalışıまで(辞書的にはçalışmak)でyorは現在形、umは主語が「私」であることを意味します。「あなたが働いている」のであればçalışıyorsunと最後がsunになります。

ドイツ語はcompound wordsがたくさんあります。例えば数字はスペースで分割しないで書きますので、組み合わせは膨大な数になります。例えば38万はdreihundertachtzigtausendになります。もし分割するのであればdrei hundert achtzig tausendになります。

ヨーロッパの言語も部分的に単語分割を必要としている言語は多数あります。

リンク

今回のデータ一式はGitHubに置いておきました。

この記事が気に入ったらサポートをしてみませんか?