StatsBeginner: 初学者の統計学習ノート

統計学およびR、Pythonでのプログラミングの勉強の過程をメモっていくノート。たまにMacの話題。

Rで距離行列を求める高速な関数

Rでクラスター分析などをするときに距離行列を求める必要があるが、次元が大きくなると(万単位とか)けっこう時間がかかる。
で、

  • 標準で入ってる{stats}のdist()
  • {Rfast}のDist()
  • {wordspace}のmatrix.dist()

を比較してみたところ、3つ目のやつが一番速く、100倍ぐらい高速になった。
以下は、5000行かける768列の元データに対して、各行のあいだの距離を求めた例です。
いずれも、いろんな距離を求めるオプションがあるが、{wordspace}のmatrix.distだけはデフォルトがコサイン類似度になってるので、ユークリッド距離にするならmethod='euclidean'をかく必要がある。

ちなみにstats::distの場合でいうと、1000行なら8秒だったのが、5000行にすると5分近くかかるようになるので、探索的に(階層的)クラスター分析をする上ではここの速度はかなり重要。

> t <- proc.time()
> distance <- stats::dist(mat)
> proc.time() - t
   user  system elapsed 
288.061   0.004 287.934 
> t <- proc.time()
> distance <- Rfast::Dist(mat)
> proc.time() - t
   user  system elapsed 
  7.982   0.000   7.979 
> t <- proc.time()
> distance <- wordspace::dist.matrix(mat, method='euclidean')
> proc.time() - t
   user  system elapsed 
  2.131   0.164   2.297 

細かい違いも一応メモっておく。

  • 入力データ
    • stats::distは、matrix型でもdata.frame型でもよい
    • Rfast::Distは、matrix型でもdata.frame型でもよい
    • wordspace::matrix.distは、は、matrix型じゃないとダメ
  • 出力データ(stats::hclustやfastcluster::hclustに与えるときの話*1
    • stats::distは、dist型なのでそのままhclustに与えてOK
    • Rfast::Distは、as.dist()してからhclustに与える
    • wordspace::matrix.distは、は、as.dist()してからhclustに与える
  • デフォルト
    • stats::distは、ユークリッド距離
    • Rfast::Distは、ユークリッド距離
    • wordspace::matrix.distは、コサイン類似度

*1:fastcluster::hclustは自分がやった範囲ではstats::hclustとあまり変わらない。

configure: error: gsl-config not found, is GSL installed? ERROR: configuration failed for package ‘RcppGSL’

こういう環境構築系の作業をいちいち書いてたらキリがないのだが、ググってすぐに解決しなかったものについては、後で助かる人がいるかもと思ってなるべく書いています。
以下はAWS(Amazon Linux)上のRでの話です。
{Rfast}というパッケージを入れる際に{RcppGSL}が必要で、

configure: error: gsl-config not found, is GSL installed?
ERROR: configuration failed for package ‘RcppGSL’

というエラーが出たので、以下のようにGSLというライブラリを入れたのだが、

$ sudo yum install gsl

下記のページに書いてるように、gsl-configが入ってないのでこれだけではダメとなる。
How to fix RcppGSL installation error gsl-config: Command not found - TechOverflow

で、Amazon LinuxはcentOS系なのでパッケージ管理がapt-getではなくyumであり、yumで入れる方法が必要なのだが、libgsl2ではなくgsl-develというのを入れればよいようだ(ここに書いてあった)。

$ sudo yum install gsl-devel

あとはこれで、

install.packages('Rfast')

すればよい。

文章を「カギ括弧に挟まれている場合以外は句点で区切る」のってどうすればいいの?

日本語のパラグラフをセンテンス単位に分割するのって、もちろんいろんなパターンをプログラムで書いていけばできると思うのだが、シンプルなコードでやろうとすると、どうなるんだろうか。
普通に考えると、

  • 「。」で区切る
  • 「?」や「!」でも区切る(これらは連続するときもある。まあ句点の連続も媒体によってはあり得るが。。。)
  • カギ括弧等(丸括弧や二重カギ括弧なども含む)に挟まれている「。!?」では区切らない
  • 改行で区切る

ぐらいのルールで区切れば、だいたいの場合はカバーできそうな気はする。もちろんこれら以外に、

  • 文中で改行されていると思われる場合は改行を無視する(素材によってはそういうものは存在しないと前提できることも多い。)
  • カギ括弧が入れ子になっている場合の対処

などを考え始めるともっとややこしくなるが。


で、Rの文字列操作で、「カギ括弧で挟まれている場合以外は句点で区切る」というのを正規表現でやろうとしたのだが、正規表現になれていないこともあり、頭がこんがらがってなかなか上手くいかない。
とりあえず、{stringr}のstr_extract_allで、


「カギ括弧開くから最短で閉じるまで or 句点を含まない文字列」の1回以上繰り返し or 句点を含まない文字列


という条件で抽出してみると、1センテンスに複数回セリフが出てくる場合や、セリフのなかで句点が複数回出る場合も含めて、抽出することができた。
以下の最後の一文のように、カギ括弧が入れ子になってると、最短マッチにしてるので崩壊する。

文例:
今日、高速道路を走っていたら後ろからパトカーが迫ってきて、「はいグレーのフリード左に寄せて停まってください。」と言うので、恐る恐る路側帯に停車した。お巡りさんが2人、降りてきた。1人が「今、進路変更するとき合図出てなかったですね。」と言い、もう1人は「ちょっとスピードも出過ぎですね。まぁ、20キロぐらいしかオーバーしてないし、今日のところは合図不履行だけで切っときますけど。」と言う。私は、「すいません、出したつもりだったんですけどね……」と答えた。最近、立て続けに「シートベルト」「一時停止」で違反を取られていて、もううんざりだ。興味本位でお巡りさんに、「そういえば昔、茨城県警に「40キロ以上オーバーしないとスピード違反は切らないよ。」と言われましたね。大阪府警も似たような方針ですか。」と訊いてみたのだが、ノーコメントだった。

> x1 <- "今日、高速道路を……省略……ノーコメントだった。"
> x2 <- str_extract_all(x1, "((「.*?」)|([^。]))+|[^。]+")
> x3 <- paste(x2[[1]], '。', sep='')  # お尻に。を付けなおす
> print(x3)
[1] "今日、高速道路を走っていたら後ろからパトカーが迫ってきて、「はいグレーのフリード左に寄せて停まってください。」と言うので、恐る恐る路側帯に停車した。"                                                        
[2] "お巡りさんが2人、降りてきた。"                                                                                                                                                                               
[3] "1人が「今、進路変更するとき合図出てなかったですね。」と言い、もう1人は「ちょっとスピードも出過ぎですね。まぁ、20キロぐらいしかオーバーしてないし、今日のところは合図不履行だけで切っときますけど。」と言う。"
[4] "私は、「すいません、出したつもりだったんですけどね……」と答えた。"                                                                                                                                            
[5] "最近、立て続けに「シートベルト」「一時停止」で違反を取られていて、もううんざりだ。"                                                                                                                          
[6] "興味本位でお巡りさんに、「そういえば昔、茨城県警に「40キロ以上オーバーしないとスピード違反は切らないよ。」と言われましたね。"                                                                                
[7] "大阪府警も似たような方針ですか。"                                                                                                                                                                            
[8] "」と訊いてみたのだが、ノーコメントだった。"  


!や?も入れる場合は、「!?」とその繰り返しにも対応するように区切り文字を[^[。!?]+]*1というふうにしておくといいが、

"((「.*?」)|([^[。!?!?]+]))+|[^[。!?!?]+]+"

その場合は「お尻に句点を付け直す」のは無駄なのでやめる。
入れ子問題以外にもいろいろ落とし穴がありそうだが、単に句点で区切るよりはだいぶマシではある。いま、新聞記事のコーパスを解析していて、新聞はそんなに変な表現が出てこないから、これぐらいシンプルなルールでもまぁまぁ行けそう。係り受け解析器とかも駆使するとさらに正確にできるのかもしれないが、知識が追いついてないのと、今やってるタスクではクオリティよりも高速で処理することのほうが優先なので、ひとまずこれ以上は考えずに進めようかな。


入れ子問題も、要するに一番外側のカッコだけ見て、その中身は何でもいいと判断すれば良いわけなので、ある程度単純なルールで行けそうな気はするのだが、自分のスキルではパッと思いつかない。「一番外側のカッコ」を最長マッチで見てしまうと、
●●「◯◯」●●。●●「◯◯」●●。
という文が一文になってしまう。先読みとか戻り読みとかを使うんかな。カッコの開閉の個数が一致することと、上位階層のクラスをまたいで開閉することはできないというルールを入れる必要があるので、正規表現でやることではないのかもしれないが。


参考記事:
日本語の文章をいい感じに文区切りするライブラリを作った - Qiita

*1:これの内側の[]を()にしてもちゃんと動いたのだが、なんで…?

AWSのR4.0.2に{devtools'}が入らない

AWSに設置したRStudio Serverで{devtools}のインストールに失敗し、以下のように依存関係のエラーが出る。(途中の行を省略している)

> ERROR: configuration failed for package ‘textshaping’
> ERROR: dependency ‘textshaping’ is not available for package ‘ragg’
> ERROR: dependency ‘ragg’ is not available for package ‘pkgdown’
> ERROR: dependency ‘pkgdown’ is not available for package ‘devtools’


たどっていくと、OS側でfribidiとかlibtiff4がないとかいう話なのだが、似たような問題で躓いてる人のコメントをググりながら以下のようなライブラリを全部インストールしたら問題が解決した。どれが効いたかは知らんw

$ sudo yum install libfreetype6-dev freetype-devel libpng-dev libjpeg-dev libtiff-devel libtiff5-dev libjpeg-turbo-devel


Rで以下のパッケージを入れる。

install.packages(c('textshaping’, 'ragg', 'pkgdown'))


すると{devtools}が入るようになる。

install.packages('devtools')


Amazon LinuxはCentOS 7に似ているとのことだが(リンク)、ツール類が最低限に絞られているようで、何かが足りなくて使いたいソフトのインストールが出来ないという現象にけっこう出くわす。Amazon LinuxではなくUbuntuやCentOSのAMIを選択したほうがストレスがないのかもしれない。

Rで{snow}と{parallel}の並列化を少し試してみた

Rで計算を高速化したいとき、

  • なるべくベクトル計算にしてforで頭からみていくような処理を避ける
  • 自作関数をコンパイルする
  • 並列化(マルチコアの利用)

などの手法があり、ベクトル化とコンパイルに関してはケースによって何が有効かというのは難しい。
ただ、forで頭から順に見ていく処理(前後の依存関係がなく、処理順を入れ替えたり、カタマリに分割しても問題がないようなもの)をやる場合に、複数のスレッドに分けて並行処理すればその分速くなるというのは直観的に理解しやすい。


色々試したわけではないので、どういう場合にどの程度並列化が有効であるかとかはよく分かってないのだが、取り急ぎコードの書き方を忘れないため程度のメモとして、以下に書き写しておく。
なお、並列化すると、時間を測った場合のuserとsystemの値がおかしくなるが、elapsedの値は合っている。(一応ストップウォッチで確認した。)

> library(snow)
> library(parallel)
> detectCores(logical = FALSE)  # 物理コア数の確認
[1] 4
> detectCores(logical = TRUE)  # 論理コア数の確認
[1] 8
> 
> # 処理の中身はどうでもいいが、ここでやっている処理が何かというと、
> # faid_allという文字列のベクトルがあり、これを頭から順にみていって、
> # d_all3というデータフレームのfile_article_idという列の値と一致する
> # 行の、content_without_tagという列に入っているテキストを連結して
> # text_allという新しいベクトルに追加していく。

> # 並列化しない場合
> t <- proc.time()
> text_all <- c()
> for(i in 1:length(faid_all)) {
+   target.rows <- which(d_all3$file_article_id==faid_all[i])
+   text.sep <- d_all3[target.rows,]$content_without_tag
+   text.paste <- paste(text.sep, collapse = '\n')
+   text_all <- c(text_all2, text.paste)
+ }
> proc.time()-t
   user  system elapsed 
 64.819  12.420  77.050 

> # {snow}のsocketで並列化
> cl <- makeCluster(8, type="SOCK")  # クラスターを8つ立ち上げ
> clusterExport(cl, c('d_all3','faid_all')) # オブジェクトをクラスターにコピー
> # クラスターを立ち上げてオブジェクトをコピーするところで10秒ぐらいかかるので、時間はここから測る。
> t <- proc.time()
> text_all <- parSapply(cl, faid_all, function(p){
+   target.rows <- which(d_all3$file_article_id==p)
+   text.sep <- d_all3[target.rows,]$content_without_tag
+   text.paste <- paste(text.sep, collapse = '\n')
+   return(text.paste)
+ })
> stopCluster(cl)  # クラスターを立ち上げ(忘れないように!)
> proc.time()-t
   user  system elapsed 
  0.098   0.054  16.365 

> # {parallel}のforkingで並列化
> t <- proc.time()
> text4 <- mclapply(faid_all, function(p){
+   target.rows <- which(d_all3$file_article_id==p)
+   text.sep <- d_all3[target.rows,]$content_without_tag
+   text.paste <- paste(text.sep, collapse = '\n')
+   return(text.paste)
+ }, mc.cores = 8)
> proc.time()-t
   user  system elapsed 
 36.652   8.208  16.077 


forkingとsocketの違いはあまり理解できてないが、socketは使用する変数を全て、各コアにコピーしなければならないらしく、そこの処理で少し余計に時間がかかる。
自分の場合、Macの物理コアが4、論理コアが8で、4本に並列化すると4倍ぐらいの速度にはなった。上の例のように8本にしても8倍にはならないのだが、4本よりは少し速かった。


以下は、AWSでvCPUが32個のマシンを借りて、とある処理にかかる時間を並列化の本数ごとに計測したもの。1回ずつしか測ってないので誤差がある。
途中からほとんど水平だが、並列化しても意味がないというより、たぶん「とある処理」の中で並列化と関係ない部分で30秒ぐらいかかってるんだろう。(vCPUは仮想CPUのことなので物理的なコア数のように比例的に増えないというのもあるかもしれないが。)

MeCabとRMeCabのインストール、NEologd辞書への変更、ユーザ辞書登録をやり直す(Mac OS)

形態素解析エンジンのMeCab(およびRMeCab)をEC2上の新しい環境に入れる必要が生じたので、

  • MeCabのインストール
  • IPA辞書のインストール
  • RMeCabのインストール
  • NEologd辞書のインストールとシステム辞書の変更
  • ユーザ辞書の作成、コンパイル、登録

の手順を改めて確認してみた。以下は手元のMac上での作業だけどlinuxでもさほど変わらんでしょう。
ちなみにRMeCabは、システム自体にインストールされたMeCabを利用するラッパーなので、R上だけではインストールが完結しない。


ソースから自分でインストールする方法もあるが、私はHomebrewで管理することにしたいので、まずHomebrewでMeCabとIPA辞書をインストールする。ターミナルで以下のようにする。

$ brew install mecab
$ brew install mecab-ipadic


ちなみにどうでもいいが、MeCab本体だけインストールした状態でmecabコマンドを打つと、

$ param.cpp(69) [ifs] no such file or directory: /usr/local/lib/mecab/dic/ipadic/dicrc

というエラーが出るが、上記の場所を探しに行っているのは、mecabrcというファイルに書かれたコンフィグでデフォルトでそう指定されているため。
最初からIPA辞書を使わないという場合は、べつにmecab-ipadicをインストールせずに、別の辞書をインストールして、コンフィグを書き換えればいいのだが、その場合は、
/usr/local/etc/mecabrc
を開いて、

$ dicdir =  /usr/local/lib/mecab/dic/ipadic


という記述の部分を書き換えることになる。ここに、コンパイル済みの別の辞書のパスを書けばいい。ちなみに後述するように、同じファイルにユーザ辞書の設定も書くことになる。


とりあえずIPA辞書のインストールまで済んだら、試しに起動してみる。

$ mecab
すもももももももものうち。
すもも	名詞,一般,*,*,*,*,すもも,スモモ,スモモ
も	助詞,係助詞,*,*,*,*,も,モ,モ
もも	名詞,一般,*,*,*,*,もも,モモ,モモ
も	助詞,係助詞,*,*,*,*,も,モ,モ
もも	名詞,一般,*,*,*,*,もも,モモ,モモ
の	助詞,連体化,*,*,*,*,の,ノ,ノ
うち	名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ
。	記号,句点,*,*,*,*,。,。,。
EOS


RのほうでRMeCabもインストールしておこう。CRANからじゃないので注意。

install.packages("RMeCab", repos = "http://rmecab.jp/R")
library(RMeCab)
RMeCabC("すもももももももものうち。")
# 結果の表示は省略


IPA辞書でMeCabを使うなら上記で完了だが、今回は、新語に強く毎週辞書が更新されているmecab-ipadic-NEologdを使いたいので、インストールする。インストール方法は以下のページに書いてある。
https://github.com/neologd/mecab-ipadic-neologd/blob/master/README.ja.md


まず、git cloneでソースをダンロードし、ダウンロードしたディレクトリに移動して、インストーラーを実行する。

$ git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git
$ cd mecab-ipadic-neologd
$ ./bin/install-mecab-ipadic-neologd -n -a

ここで-aというオプションは、上記説明ページにある「全部入り」の意味。けっこうインストールに時間かかる。
さて、インストールしただけではNEologd辞書は使えない。以下のように解析を実行してみると……

$ mecab
今日はあつまれどうぶつの森をプレイします。
今日	名詞,副詞可能,*,*,*,*,今日,キョウ,キョー
は	助詞,係助詞,*,*,*,*,は,ハ,ワ
あつまれ	動詞,自立,*,*,五段・ラ行,命令e,あつまる,アツマレ,アツマレ
どう	副詞,助詞類接続,*,*,*,*,どう,ドウ,ドー
ぶつ	名詞,一般,*,*,*,*,ぶつ,ブツ,ブツ
の	助詞,連体化,*,*,*,*,の,ノ,ノ
森	名詞,一般,*,*,*,*,森,モリ,モリ
を	助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
プレイ	名詞,一般,*,*,*,*,*
し	動詞,自立,*,*,サ変・スル,連用形,する,シ,シ
ます	助動詞,*,*,*,特殊・マス,基本形,ます,マス,マス
。	記号,句点,*,*,*,*,。,。,。
EOS


このように「あつまれどうぶつの森」が固有名詞として認識されないのは、システム辞書としてデフォルトのIPA辞書が適用されたままだからである。
NEologd辞書をMeCabに反映させる方法は2つある。

  1. MeCabコマンドを実行するときに、システム辞書を指定する。(RMeCabではこの方法は使えない。)
  2. /usr/local/etc/mecabrcを書き換えてデフォルトのシステム辞書を入れ替える。


前者は、以下のようにmecabコマンドの後ろに-dオプションを付けて辞書を指定する。ちなみに後でやるように、ユーザ辞書を指定する場合は-uで指定するのだが、その場合はディレクトリじゃなくてファイルのパスを指定するところが違うので注意。システム辞書はディレクトリで指定する。

$ mecab -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd/
今日はあつまれどうぶつの森をプレイします。
今日	名詞,副詞可能,*,*,*,*,今日,キョウ,キョー
は	助詞,係助詞,*,*,*,*,は,ハ,ワ
あつまれどうぶつの森	名詞,固有名詞,一般,*,*,*,あつまれどうぶつの森,アツマレドウブツノモリ,アツマレドーブツノモリ
を	助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
プレイ	名詞,固有名詞,一般,*,*,*,PLAY!,プレイ,プレイ
し	動詞,自立,*,*,サ変・スル,連用形,する,シ,シ
ます	助動詞,*,*,*,特殊・マス,基本形,ます,マス,マス
。	記号,句点,*,*,*,*,。,。,。
EOS


しかしRのRMeCabから使う場合は、この方法は使えない(RMeCabのdicという引数はユーザ辞書を指定するためのもの。)
そこで、コンフィグでデフォルトのシステム辞書を変更するために、/usr/local/etc/mecabrcを書き換えるのだが、最初は開くと以下のような内容になっている。

; Configuration file of MeCab
;
; $Id: mecabrc.in,v 1.3 2006/05/29 15:36:08 taku-ku Exp $;
;
dicdir =  /usr/local/lib/mecab/dic/ipadic

; userdic = /home/foo/bar/user.dic

; output-format-type = wakati
; input-buffer-size = 8192

; node-format = %m\n
; bos-format = %S\n
; eos-format = EOS\n


dicdir=がシステム辞書のパスを書くところで、userdic=はユーザ辞書のパスを書くところ(最初は;でコメントアウトされている)。
とりあえずここでは、以下のように書き換えておく。テキストエディタで開けばよいが、管理者権限になってて保存できなかったりする場合はターミナルからsudo viとか編集する。

dicdir =  /usr/local/lib/mecab/dic/mecab-ipadic-neologd/


これでシステム辞書が切り替わったので、以下のように、オプションを付けなくても「あつまれどうぶつの森」が一つの固有名詞として判定される。

$ mecab
今日はあつまれどうぶつの森をプレイします。
今日	名詞,副詞可能,*,*,*,*,今日,キョウ,キョー
は	助詞,係助詞,*,*,*,*,は,ハ,ワ
あつまれどうぶつの森	名詞,固有名詞,一般,*,*,*,あつまれどうぶつの森,アツマレドウブツノモリ,アツマレドーブツノモリ
を	助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
プレイ	名詞,固有名詞,一般,*,*,*,PLAY!,プレイ,プレイ
し	動詞,自立,*,*,サ変・スル,連用形,する,シ,シ
ます	助動詞,*,*,*,特殊・マス,基本形,ます,マス,マス
。	記号,句点,*,*,*,*,。,。,。


Rの方でもちゃんと認識できる。

> RMeCabC("今日はあつまれどうぶつの森をプレイします。")
[[1]]
  名詞 
"今日" 

[[2]]
助詞 
"は" 

[[3]]
                  名詞 
"あつまれどうぶつの森" 

[[4]]
助詞 
"を" 

[[5]]
    名詞 
"プレイ" 

[[6]]
動詞 
"し" 

[[7]]
助動詞 
"ます" 

[[8]]
記号 
"。" 


さて次に、ユーザ辞書を登録する。例えば以下のように、「95%信頼区間」は複数の単語に分解されてしまうのだが(文脈にもよる可能性があるが)、これを辞書に登録しておいて1つの名詞として認識させたい。

$ mecab
今日は95%信頼区間の求め方を勉強します。
今日	名詞,副詞可能,*,*,*,*,今日,キョウ,キョー
は	助詞,係助詞,*,*,*,*,は,ハ,ワ
95%	名詞,固有名詞,一般,*,*,*,95%,キュウジュウゴパーセント,キュウジュウゴパーセント
信頼	名詞,サ変接続,*,*,*,*,信頼,シンライ,シンライ
区間	名詞,一般,*,*,*,*,区間,クカン,クカン
の	助詞,連体化,*,*,*,*,の,ノ,ノ
求め	動詞,自立,*,*,一段,連用形,求める,モトメ,モトメ
方	名詞,接尾,特殊,*,*,*,方,カタ,カタ
を	助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
勉強	名詞,サ変接続,*,*,*,*,勉強,ベンキョウ,ベンキョー
し	動詞,自立,*,*,サ変・スル,連用形,する,シ,シ
ます	助動詞,*,*,*,特殊・マス,基本形,ます,マス,マス
。	記号,句点,*,*,*,*,。,。,。
EOS


ユーザ辞書を使う方法はここに書いてある。
http://taku910.github.io/mecab/dic.html
まずMeCabのフォーマットにしたがったCSVファイル(タイトル行は不要)を作成し、それをコンパイルして、/usr/local/etc/mecabrcのユーザ辞書欄にパスを追加するか、もしくは解析をするときにオプションで指定する。
ユーザ辞書はどこに置いててもいいのだが、私は/usr/local/lib/mecab/dic/の中にuserdicというフォルダを作って置いておくことにした。
そのフォルダの中にまず、以下のような内容のcsvをuserdic1.csvという名前で保存する(名前は何でもいいが)。文字コードはUTF-8にしておく。

95%信頼区間,1285,1285,5000,名詞,一般,*,*,*,*,95%信頼区間,キュウジュウゴパーセントシンライクカン,キュージューゴパーセントシンライクカン


一番左が、文章中に出てくる実際の表記で、右から3つ目は基本形。左から2つ目と3つ目のIDは、左文脈ID、右文脈IDというらしいが、空にしておいてもコンパイル時に勝手に埋めてくれるらしい。私はよく分かってないが、システム辞書のコンパイル前のcsvを見て似た単語と同じIDを入れておいた。
左から4つ目の5000という数字は、その単語の登場しやすさを表していて、値を小さくすると出現頻度の高い単語ということになるので、解析時に1つの単語として認識される確率が高くなる。
このコストの数字も、システム辞書のコンパイル前のcsvを見て似た単語のコストを書いとけばいいらしい。認識されやすくするなら、小さい値を設定する。


つぎにこのcsvをコンパイルして、MeCabが読めるユーザ辞書にするのだが、上のリンク先に書いてあるコンパイル方法だと、mecab-dict-indexという実行ファイル(コンパイラ兼インストーラ)が/usr/local/libexec/mecab/というディレクトリに置いてあることになっている。
私も以前はそうだったのだが、いったん最初からMeCabを入れ直したらMac上では/usr/local/Cellar/mecab/0.996/libexec/mecabというディレクトリに入っていた。
なお、場所が分からなければ、ターミナルから

$ sudo find / -name mecab-dict-index

として探せばよい。


ユーザ辞書をコンパイルするには、以下のようにする。
辞書置き場に移動した上で、最初のmecab-dict-indexまでが実行ファイルを指定。-d オプションのところはどのシステム辞書を使っているかを書く。-uは生成されるコンパイル済みユーザ辞書のパスとファイル名。-fと-tはcsvとコンパイル済み辞書の文字コード。そして最後にcsvのパスを指定。
システム辞書の指定が間違っていたり、文字コードの指定が間違っていたりすると、ちゃんと動作しない辞書ができて、その状態でうっかりRMeCabから呼び出すとRのセッションごと落ちるので注意したい。

$ cd /usr/local/lib/mecab/dic/userdic
$ /usr/local/Cellar/mecab/0.996/libexec/mecab/mecab-dict-index -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd -u userdic1.dic -f utf-8 -t utf-8 userdic1.csv

reading userdic1.csv ... 1
emitting double-array: 100% |###########################################| 

done!


これでコンパイル完了したので、試しに使ってみる。

$ mecab -u userdic1.dic
今日は95%信頼区間の求め方を勉強します。
今日	名詞,副詞可能,*,*,*,*,今日,キョウ,キョー
は	助詞,係助詞,*,*,*,*,は,ハ,ワ
95%信頼区間	名詞,一般,*,*,*,*,95%信頼区間,キュウジュウゴパーセントシンライクカン,キュージューゴパーセントシンライクカン
の	助詞,連体化,*,*,*,*,の,ノ,ノ
求め	動詞,自立,*,*,一段,連用形,求める,モトメ,モトメ
方	名詞,接尾,特殊,*,*,*,方,カタ,カタ
を	助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
勉強	名詞,サ変接続,*,*,*,*,勉強,ベンキョウ,ベンキョー
し	動詞,自立,*,*,サ変・スル,連用形,する,シ,シ
ます	助動詞,*,*,*,特殊・マス,基本形,ます,マス,マス
。	記号,句点,*,*,*,*,。,。,。
EOS


ちゃんと認識できてるようだ。
RMeCabでもやっておく。dicという引数にユーザ辞書のパスを書く。

> RMeCabC("今日は95%信頼区間の求め方を勉強します。",
+         dic='/usr/local/lib/mecab/dic/userdic/userdic1.dic')
[[1]]
  名詞 
"今日" 

[[2]]
助詞 
"は" 

[[3]]
         名詞 
"95%信頼区間" 

[[4]]
助詞 
"の" 

[[5]]
  動詞 
"求め" 

[[6]]
名詞 
"方" 

[[7]]
助詞 
"を" 

[[8]]
  名詞 
"勉強" 

[[9]]
動詞 
"し" 

[[10]]
助動詞 
"ます" 

[[11]]
記号 
"。" 


これは先ほど言ったように、mecabrcの中にユーザ辞書の指定を書き込むことも可能で、mecabrcに以下のように追記する。システム辞書(dicdir)はディレクトリ、ユーザ辞書はファイルを指定するというところを間違えやすいので注意が必要。ちなみに、ユーザ辞書はカンマで区切って複数のパスを書けば複数同時に使えるらしい。

; Configuration file of MeCab
;
; $Id: mecabrc.in,v 1.3 2006/05/29 15:36:08 taku-ku Exp $;
;
dicdir =  /usr/local/lib/mecab/dic/mecab-ipadic-neologd/

userdic = /usr/local/lib/mecab/dic/userdic/userdic1.dic

; output-format-type = wakati
; input-buffer-size = 8192

; node-format = %m\n
; bos-format = %S\n
; eos-format = EOS\n


ちなみに、NEolodgに切り替えると、「すもももももももものうち。」が解析できなくなる。
すもももももももものうち · Issue #41 · neologd/mecab-ipadic-neologd · GitHub