mecab-ipadic-NEologdの単語更新が2020年あたりで止まっているようですので、それ以降に登場した単語が解析できません。
例えば最近の人気アニメの”スパイファミリー”を解析しようとすると、
スパイファミリー
スパイ 名詞,一般,*,*,*,*,スパイ,スパイ,スパイ
ファミリー 名詞,一般,*,*,*,*,ファミリー,ファミリー,ファミリー
EOS
”スパイ”と”ファミリー”の2単語で解析されてしまいます。
neologdでははてなキーワードのダンプデータ等、様々なweb上の資源から辞書を作成していたようですが、せめてwikipediaに掲載されている固有名詞くらいは解析したいと思い、最新のwikipediaダンプデータ(2023年1月版)からユーザー辞書(システム辞書ではない)を作成したいと思います。
まずは日本語wikiページの全タイトルが記載されたダンプデータをこちらからダウンロードしてきます(今回は jawiki-20230120-all-titles-in-ns0.gz というファイルになります)。
ファイル内の単語数を見てみると2202077個あるようです。膨大な数ですが、よく見てみると'1917'等の単なる数字だったり'2005年のスポーツ'など固有名詞とは言えないエントリも多く含まれていますので、不要なものは除外したいです。
そこで前処理としてダンプファイルのフォーマットを以下の30個のルールで整えていきます。
1 | 前処理パターン | アンダーバー(_) |
対応 | 半角スペースに変換 | |
2 | 前処理パターン | 全角英数字・記号 |
対応 | neologdn辞書用の正規化処理の実施(neologdnモジュール) | |
3 | 前処理パターン | 単語末尾_() or 単語末尾() |
対応 | 除去するべき場合としないほうが良い場合の判定難しため、末尾が括弧閉じで終わる場合のみ除外 | |
例 | LAST_GIGS_(Video) | |
$10_(曲) | ||
&_(シングル) | ||
/e/_(オペレーティングシステム) | ||
0.03秒_(お笑いトリオ) | ||
Creepy_Nuts(R-指定&DJ松永) | ||
LEVEL3(アナログ盤) | ||
... | ||
4 | 前処理パターン | 引用符(",')が含まれる |
対応 | 単語全体が引用符(",')で含まれる場合のみ、引用符を除外して追加する | |
例 | ”Hello,_world.” | |
”Show_me_the_way” | ||
”THE_RAIL_KITCHEN_CHIKUGO” | ||
... | ||
5 | 前処理パターン | 引用符'が2つ以上連続するケース |
対応 | 2つ以上連続するシングルクオーテーションはダブルクオーテーション1つに変換 | |
''ブレイブリーデフォルト_フェアリーズエフェクト''' | ||
'N''-ビニル-2-ピロリドン | ||
'O''記法 | ||
'j''-不変量 | ||
11'09''01/セプテンバー11 | ||
3''-デアミノ-3''-ニコチアナミンレダクターゼ | ||
... | ||
6 | 前処理パターン | 単語1文字 |
対応 | 全除外 | |
例 | & | |
% | ||
7 | 前処理パターン | 単語16文字以上 |
対応 | 全除外 | |
8 | 前処理パターン | ,(カンマ)が含まれる |
対応 | 全除外 | |
例 | Yes,mama_ok? | |
Yes,we_are. | ||
Yesterday,_Yes_a_day | ||
You're_a_Sap,_Mr._Jap | ||
... | ||
9 | 前処理パターン | ~の・・ |
対応 | 単語内に'の'が含まれる単語は全除外(文頭・文末が'の'の場合は助詞の'の'の可能性は低いので例外で登録. ex. 'のの子突撃','ののいちカレード',) | |
例 | チュニジアの旗 | |
ガンビア銀行の一覧 | ||
ナウルと日本の関係 | ||
... | ||
10 | 前処理パターン | ~及び(および)・・・ |
対応 | 除外 | |
例 | 外交部及び国際事務学院 | |
2010年憲法改革及び統治法 | ||
マケドニア共和国空軍及び防空軍 | ||
基準割引率および基準貸付利率 | ||
... | ||
11 | 前処理パターン | ~または・・・ |
対応 | 除外 | |
例 | 賢者の石、または魔法の島 | |
やとみまたはち | ||
および/または | ||
12 | 前処理パターン | 動詞,形容詞 |
対応 | 下記正規表現に該当する動詞+”^.+い”で終わる形容詞すべて除外 | |
例 | 攣る | |
嚙む | ||
... | ||
13 | 前処理パターン | ひらがな2文字の単語 |
対応 | 除外 | |
14 | 前処理パターン | 会社名 |
対応 | 現状除外していない | |
例 | (有)櫻井工房 | |
(株)かっこかぶ | ||
(有)チェリーベル | ||
(株)あまつか笑事 | ||
.. | ||
15 | 前処理パターン | 索引~ |
対応 | 一部例外除いて除外 | |
除外例 |
索引ひ |
|
索引Z | ||
索引1 | ||
索引う | ||
索引K | ||
... | ||
例外 | 索引記号 | |
索引順編成ファイル | ||
索引付き順次アクセス方式 | ||
16 | 前処理パターン | 引用符すべて |
対応 | 引用符はすべてシングルクオーテーションに統一 | |
特殊引用符例 | “SINGLES” | |
“SMILING”_〜THE_BEST_OF_NORIYUKI_MAKIHARA〜 | ||
“SUMMER_of_'98”pure_soul_in_STADIUM | ||
“Start_Walking_The_World”TOUR | ||
“The_Book”jojo's_bizarre_adventure_4th_another_day | ||
“UTAHIME”_AKINA_NAKAMORI_PARCO_THEATER_LIVE | ||
“X”plosion_GUNDAM_SEED | ||
17 | 前処理パターン | ダンプファイル内で文字の一部が重複している単語 |
対応 | 重複があるとmecabで分割されてしまうため,すべて除外→ユーザー辞書作成後に再度追加予定 | |
18 | 前処理パターン | アルファべット or '!', '?' のみが連続する単語 |
対応 | 除外 | |
19 | 前処理パターン | ハッシュタグ(#ではじまる) |
例 | #5,1288,1288,7911,名詞,固有名詞,一般,*,*,*,#5 #3,1288,1288,7911,名詞,固有名詞,一般,*,*,*,#3 #4,1288,1288,7911,名詞,固有名詞,一般,*,*,*,#4 #17,1288,1288,7437,名詞,固有名詞,一般,*,*,*,#17 #2i2,1288,1288,6815,名詞,固有名詞,一般,*,*,*,#2i2 #302,1288,1288,6815,名詞,固有名詞,一般,*,*,*,#302 #SOAR,1288,1288,5957,名詞,固有名詞,一般,*,*,*,#SOAR #ハピイレ,1288,1288,5957,名詞,固有名詞,一般,*,*,*,#ハピイレ ... |
|
対応 | 除外 | |
20 | 前処理パターン | ?が先頭の単語 |
例 | "?日,1288,1288,7911,名詞,固有名詞,一般,*,*,*,?日 ?月,1288,1288,7911,名詞,固有名詞,一般,*,*,*,?月 ?:,1288,1288,7911,名詞,固有名詞,一般,*,*,*,?: ?年,1288,1288,7911,名詞,固有名詞,一般,*,*,*,?年 ??日,1288,1288,7437,名詞,固有名詞,一般,*,*,*,??日 ... |
|
対応 | 除外 | |
21 | 前処理パターン | 句読点連続 |
例 | 、。 | |
対応 | 除外 | |
22 | 前処理パターン | 文末点の連続 |
例 | ・・・,1288,1288,-648,名詞,固有名詞,一般,*,*,*,・・・ ・・・・・・・・・,1288,1288,-8974,名詞,固有名詞,一般,*,*,*,・・・・・・・・・ ...,1288,1288,7437,名詞,固有名詞,一般,*,*,*,... ....,1288,1288,6815,名詞,固有名詞,一般,*,*,*,.... |
|
対応 | 除外 | |
23 | 前処理パターン | ひらがな以外(漢字,カナ,アルファベット,数字)+さん/ちゃん |
例 | ['京子ちゃん'] ['阿部ちゃん'] |
|
対応 | 除外 | |
24 | 前処理パターン | アンダーバー連続 |
例 | __ | |
対応 | 除外 | |
25 | 前処理パターン | 数字連続+感嘆符 |
例 | 9!,1288,1288,7911,名詞,固有名詞,一般,*,*,*,9! 6!,1288,1288,7911,名詞,固有名詞,一般,*,*,*,6! 7!,1288,1288,7911,名詞,固有名詞,一般,*,*,*,7! 4!,1288,1288,7911,名詞,固有名詞,一般,*,*,*,4! 3!,1288,1288,7911,名詞,固有名詞,一般,*,*,*,3! 5!,1288,1288,7911,名詞,固有名詞,一般,*,*,*,5! 5656!,1288,1288,5957,名詞,固有名詞,一般,*,*,*,5656! 1518!,1288,1288,5957,名詞,固有名詞,一般,*,*,*,1518! |
|
対応 | 除外 | |
26 | 前処理パターン | マイナス+数字連続 |
例 | -8,1288,1288,7911,名詞,固有名詞,一般,*,*,*,-8 -9,1288,1288,7911,名詞,固有名詞,一般,*,*,*,-9 -0,1288,1288,7911,名詞,固有名詞,一般,*,*,*,-0 -7,1288,1288,7911,名詞,固有名詞,一般,*,*,*,-7 -6,1288,1288,7911,名詞,固有名詞,一般,*,*,*,-6 -5,1288,1288,7911,名詞,固有名詞,一般,*,*,*,-5 ... |
|
対応 | 除外 | |
27 | 前処理パターン | コロン+数字 |
例 | 18:0,1288,1288,6815,名詞,固有名詞,一般,*,*,*,18:0 22:5,1288,1288,6815,名詞,固有名詞,一般,*,*,*,22:5 20:5,1288,1288,6815,名詞,固有名詞,一般,*,*,*,20:5 8:46,1288,1288,6815,名詞,固有名詞,一般,*,*,*,8:46 18:1,1288,1288,6815,名詞,固有名詞,一般,*,*,*,18:1 22:6,1288,1288,6815,名詞,固有名詞,一般,*,*,*,22:6 ... |
|
対応 | 除外 | |
28 | 前処理パターン | スラッシュ+数字 |
例 | 1/,1288,1288,7911,名詞,固有名詞,一般,*,*,*,1/ /0,1288,1288,7911,名詞,固有名詞,一般,*,*,*,/0 /05,1288,1288,7437,名詞,固有名詞,一般,*,*,*,/05 2/4,1288,1288,7437,名詞,固有名詞,一般,*,*,*,2/4 1/5,1288,1288,7437,名詞,固有名詞,一般,*,*,*,1/5 1/4,1288,1288,7437,名詞,固有名詞,一般,*,*,*,1/4 ... |
|
対応 | 除外 | |
29 | 前処理パターン | ハイフン連続 |
例 | --,1288,1288,7911,名詞,固有名詞,一般,*,*,*,-- ---,1288,1288,7437,名詞,固有名詞,一般,*,*,*,--- |
|
対応 | 除外 | |
30 | 前処理パターン | アルファベット1文字+'.' |
例 | D.,1288,1288,7911,名詞,固有名詞,一般,*,*,*,D. E.,1288,1288,7911,名詞,固有名詞,一般,*,*,*,E. L.,1288,1288,7911,名詞,固有名詞,一般,*,*,*,L. V.,1288,1288,7911,名詞,固有名詞,一般,*,*,*,V. |
|
対応 | 除外 |
次に単語の生起コスト設定の方法ですが、新規で追加した単語が他の単語で分割されないように設定します。
例えば "スパイファミリー"(固有名詞)と登録したのに既存エントリの"スパイ"(名詞) と "ファミリー"(名詞)に分割されるのを防ぎます。そのために既存辞書の最短のコスト値から-1以下に設定します。
ここでコストを下げすぎると既存辞書にその単語を含む単語がある場合に、既存の単語が選ばれなくなる可能性が出てきます。例としては”スパイファミリー2"という既存単語があった場合に、新規で"スパイファミリー”をコスト最強-9999等で設定してしまうと"スパイファミリー2"はどのような文脈でも解析結果に出現しなくなってしまいます。
では-1に設定すれば良いのでは?と考えるのですが、既存単語(固有名詞)のコスト値とあまりにもかけ離れた値を設定してしまう可能性(固有名詞としてはコスト値が高すぎて、文脈の中では正しく解析されない可能性)もありますので、あらかじめ全既存単語の文字数ごとにコスト値の平均値を調べておき、その"平均値"と先ほどの"最短のコスト値-1"の低い方の値を最適なコスト値として設定することにします。
登録する単語の前処理を行い、設定する生起コスト値も決まったわけですが、ここで一つ問題が出てきます。
もしダンプファイル内に文字が重複する単語があった場合どうするか?ということです。
例えばダンプファイル内に”スパイファミリー”と”スパイファミリー2”の2単語があった場合、これらの単語のコスト値を求める際に、お互いの単語のコスト値は考慮されません。つまり文字数の多い"スパイファミリー2"のコスト値が文字数の少ない"スパイファミリー”より高くなりすぎて、"スパイファミリー2"という文章を解析する際に"スパイファミリー"と"2"の2単語に分割されてしまう可能性が出てきます。
そこでダンプファイル内の単語すべてを一度にコスト設定するのではなく、文字が一部重複する単語群を保留しておいて、文字数が少ない単語群から複数回に分けてコストを設定していくというプロセスを取ることにします。
前置きが長くなりましたが、上記の前処理規則・コスト設定手順を適用して作成されたユーザー辞書がこちらになります。
辞書の元になったcsvファイルの単語総数は778031個です。この数は上でご紹介した30個の前処理規則を通し、既存のneologd辞書に載っている単語は除いた数になります。
ではこのユーザー辞書を使い”スパイファミリー”を解析してみましょう。
スパイファミリー 名詞,固有名詞,一般,*,*,*,スパイファミリー
EOS
新規で追加された固有名詞の”スパイファミリー”1語で解析できました。
では”スパイファミリー”以外の新規単語も正しく解析できるのでしょうか?またユーザー辞書を加えたことによる、既存のシステム辞書への悪影響はないのでしょうか?そこで以下4つのテストを実施してみます。
1.解析する文章が新規追加した単語のみの場合、他の単語に分割されずに解析されるか?
2.解析する文章が新規追加した単語を含む文章の場合でも、その単語は新規の固有名詞として解析されるか?
3.解析する文章がダンプファイルに含まれていない既知の単語のみの場合、(新規追加した単語に)分割されずに解析されるか?
4.解析する文章がダンプファイルに含まれていない既知の単語を含む文章の場合でも、その単語は既知の単語のまま解析されるか?
詳細なテスト結果はこちら
テスト1と2の結果から新規追加した単語すべてが(様々な文脈において)正しく解析でき、3と4の結果から既存辞書への大きな悪影響もないことがわかりました。
これで最新wikipediaに掲載されている単語を反映したMeCabユーザー辞書を作ることができました。
今回は全単語を固有名詞・一般として(無理やり)一括登録しましたが、もう少し工夫すれば品詞の細かい分類(人名等)もできそうですね。また前処理もかなりざっくりした規則なので、実際はもう少し慎重に規則を考える必要がありそうです。
最後に、今回作成したユーザー辞書を使った解析例として、最新の人気アニメジョジョの奇妙な冒険 ストーンオーシャンの評判分析をご紹介させていただき、記事の終わりとさせていただきます。最後までお読みいただきありがとうございました。
こちらの記事もどうぞ:動詞や形容詞をユーザー辞書に登録する