PHPで MeCabのユーザー辞書を作成する

(1/1)
PHPとKAKASIを使って単語に分解する」では形態素解析ツール「KAKASI」を紹介したが、今回は、奈良先端科学技術大学院大学出身、現GoogleソフトウェアエンジニアでGoogle 日本語入力開発者の一人である工藤拓さんが開発している「MeCab」のユーザー辞書の作り方を説明する。
ユーザー辞書は、Wikipediaの見出し語をすべて取り込むことにする。

(2020年10月25日)見出し語は平仮名・片仮名・漢字を含むものに限定した。

サンプル・プログラムのダウンロード

圧縮ファイルの内容
makeudic_mecab.phpサンプル・プログラム本体
このプログラムを実行するには、MeCab がインストールされている必要がある。MeCab の入手方法やインストール方法については公式サイトを参照されたい。
MeCabChaSen をもとに開発が始まった。ChaSenに比べて解析精度は同程度で、解析速度は平均3~4倍速いという。

準備:各種定数

0024: //MeCab実行プログラム
0025: define('MECAB', 'C:\Program Files (x86)\MeCab\bin\mecab.exe');
0026: 
0027: //MeCab辞書作成プログラム
0028: define('MECABDICT', 'C:\Program Files (x86)\MeCab\bin\mecab-dict-index.exe');
0029: 
0030: //システム辞書
0031: define('PATH_SYSDIC_MECAB', 'C:\Program Files (x86)\MeCab\dic\ipadic');
0032: 
0033: //ユーザー辞書
0034: define('FILE_UDIC_MECAB', 'user_wiki.dic');
0035: 
0036: //Wikipedia見出しファイル
0037: define('TITLES_WIKIPEDIA', 'http://download.wikimedia.org/jawiki/latest/jawiki-latest-all-titles-in-ns0.gz');
0038: 
0039: //Wikipedia見出しファイル保存ファイル名
0040: define('FILE_WIKIPEDIA', 'jawiki-latest-all-titles-in-ns0.gz');
0041: 
0042: //ユーザー辞書CSV
0043: define('FILE_WIKIPEDIA_CSV', 'user_wiki.csv');

まず、各種パラメータを定数に設定する。

Wikipediaの見出し語は、"https://dumps.wikimedia.org/jawiki/latest/jawiki-latest-all-titles-in-ns0.gz" からダウンロードできる。これを定数 TITLES_WIKIPEDIA に格納する。

解説:ユーザー辞書作成

0133: /**
0134:  * ユーザー辞書を作成する
0135:  * @param string $encode文字コード
0136:  * @return string処理結果
0137: */
0138: function make_userdic($encode) {
0139:     //平均コストテーブル
0140:     static $table = array(
0141:         0,
0142:         7697, 7087, 7572, 7441, 7566, 7352, 6810, 6209, 5871, 5963,
0143:         5847, 5818, 5829, 5990, 5955, 5590, 5984, 5181, 5122, 5985,
0144:         5122, 5122, 5122, 4437, 5122
0145:     );
0146: 
0147:     $msg = 'ユーザー辞書ファイルを作成しました.';
0148: 
0149:     $buff = file_get_contents(TITLES_WIKIPEDIA);
0150:     if ($buff == FALSEreturn 'エラー:Wikipediaタイトル・ファイルが見当たりません.';
0151:     $res = file_put_contents(FILE_WIKIPEDIA$buff);
0152:     if ($res == FALSE)  return 'エラー:Wikipediaタイトル・ファイルをダウンロードできません.';
0153: 
0154:     $infp = gzopen(FILE_WIKIPEDIA, 'r');
0155:     if ($infp == FALSEreturn 'エラー:Wikipediaタイトル・ファイルを読み込めません.';
0156:     $outfp = fopen(FILE_WIKIPEDIA_CSV, 'w');
0157:     if ($infp == FALSEreturn 'エラー:ユーザー辞書ファイルを作成できません.';
0158: 
0159:     while (! feof($infp)) {
0160:         $str = trim(gzgets($infp));
0161:         if (preg_match('/[^ぁ-んァ-ヶー一-龠]/ui', $str) == 1)   continue;
0162: /**
0163:         if (preg_match('/^[0-9|a-z|\W_]/ui', $str) == 1) continue;
0164:         if (preg_match('/_/ui', $str) == 1)                   continue;
0165:         if (preg_match('/曖昧さ回避/ui', $str) == 1)       continue;
0166:         if (preg_match('/一覧/ui', $str) == 1)               continue;
0167:         if (preg_match('/の登場人物/ui', $str) == 1)       continue;
0168: **/
0169:         if (mb_strlen($str) <= 1)                           continue;
0170: 
0171:         //コスト計算
0172:         $len = mb_strlen($str);
0173:         $cost = ($len > count($table) - 1) ? 5000 : $table[$len];
0174:         $outstr = $str . ',128,128,' . $cost . ',名詞,固有名詞,*,*,*,*,' . $str . ",*,*,wikipedia\n";
0175:         if ($encode != INTERNAL_ENCODING) {
0176:             $outstr = mb_convert_encoding($outstr$encodeINTERNAL_ENCODING);
0177:         }
0178:         $res = fwrite($outfp$outstr);
0179:         if ($res == FALSE) {
0180:             $msg = 'エラー:ユーザー辞書ファイルを作成できません.';
0181:             break;
0182:         }
0183:     }
0184:     fclose($outfp);
0185:     gzclose($infp);
0186: 
0187:     $cmd = '"' . MECABDICT . '" -d "' . PATH_SYSDIC_MECAB . '" -u "' . FILE_UDIC_MECAB .'" -f ' . $encode .' -t ' . $encode . ' ' . FILE_WIKIPEDIA_CSV;
0188:     exec($cmd);
0189: 
0190:     unlink(FILE_WIKIPEDIA);
0191:     unlink(FILE_WIKIPEDIA_CSV);
0192: 
0193:     return $msg;
0194: }

TITLES_WIKIPEDIA は圧縮ファイルのため、組み込み関数  gzgets  を使って読み込む。だが、 gzopen  はローカルドライブにしか対応していないので、 file_get_contents  と  file_put_contents  を使ってローカルドライブにコピーする。

 gzgets  を使って1行ずつ読み込み、ユーザー辞書作成のためのCSV形式に変換して FILE_WIKIPEDIA_CSV に出力する。
なお、TITLES_WIKIPEDIA には辞書として登録する必要のない見出しもあるので、これらは  preg_match  によって弾いている。

CSV形式のフォーマットは以下の通り。

表層形,左文脈ID,右文脈ID,コスト,品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用形,活用型,原形,読み,発音


ここでは、左文脈IDと右文脈IDは128で固定にした。

コストは、その単語がどれだけ出現しやすいかを示している。小さいほど出現しやすいという意味になる。
ここでは、単語の文字列長に応じてコストを決定するテーブル $table を用意した。
このテーブルの値は、MeCabに標準で用意されているシステム辞書のコストの平均値を計算したものである。具体的には、'MeCab/dic/ipadic' に格納されているCSVファイルから、文字列長とコストをとりだし、文字列長毎のコストの平均を計算した。
このアイデアについては、「wikipediaのデータや顔文字辞書からmecabのユーザ辞書を作成するフレームワーク」を参考にした。

CSVファイル FILE_WIKIPEDIA_CSV が作成できたら、ここからMeCabの辞書作成ツール "mecab-dict-index"(定数 MECABDICT に定義)を使って辞書ファイルを作成する。

参考サイト

(この項おわり)
header