トップ 履歴 一覧 Farm ソース 検索 ヘルプ RSS ログイン

RcppMeCabとRMeCabの比較


キーワード

最終更新時間:2019年09月04日 14時48分48秒
アフィリエイト・広告について
プライバシーポリシー

この記事はRcppMeCabとtidytextではじめるテキストマイニングシリーズの一部です。

目次


RからMeCabを呼び出す「定番」パッケージとして、RMeCabがあります。ここでは、RcppMeCabとRMeCabの動作を、以下の観点で比較してみます。なお、自分でも比較してみたい、という方以外は、RMeCabを別途インストールする必要はありません。

RMeCabパッケージのインストール

RMeCabパッケージはCRANに登録されていないため、開発者のサイトからインストールします。install.packages() 関数に repos = "URL" オプションを指定してダウンロード、インストールします。

# Windowsの場合
install.packages("RMeCab", repos = "http://rmecab.jp/R")
# Mac あるいは Linux の場合
install.packages("RMeCab", repos = "http://rmecab.jp/R", type = "source")

なお、RMeCabは最新のUbuntuのgcc (gcc-7など) では正常にコンパイルできないことがあります。その場合、apt コマンドで g++-5 パッケージをインストールし、/usr/lib/R/etc/Makeconf ファイルを以下のように変更したうえで、上記の関数を実行する必要があります。

--- Makeconf.org        2019-09-03 09:23:39.087685600 +0900
+++ Makeconf    2019-09-03 09:23:23.981571300 +0900
@@ -12,19 +12,19 @@
 AR = ar
 BLAS_LIBS = -lblas
 C_VISIBILITY = -fvisibility=hidden
-CC = gcc -std=gnu99
+CC = gcc-5 -std=gnu99
 CFLAGS = -g -O2 -fdebug-prefix-map=/build/r-base-uuRxut/r-base-3.6.1=. (長いので省略)
 CPICFLAGS = -fpic
 CPPFLAGS =
-CXX = g++ -std=gnu++11
+CXX = g++-5 -std=gnu++11
 CXXCPP = $(CXX) -E
 CXXFLAGS = -g -O2 -fdebug-prefix-map=/build/r-base-uuRxut/r-base-3.6.1=. (長いので省略)
 CXXPICFLAGS = -fpic
-CXX98 = g++
+CXX98 = g++-5
 CXX98FLAGS = -g -O2 -fdebug-prefix-map=/build/r-base-uuRxut/r-base-3.6.1=. (長いので省略)
 CXX98PICFLAGS = -fpic
 CXX98STD = -std=gnu++98
-CXX11 = g++
+CXX11 = g++-5
 CXX11FLAGS = -g -O2 -fdebug-prefix-map=/build/r-base-uuRxut/r-base-3.6.1=. (長いので省略)
 CXX11PICFLAGS = -fpic
 CXX11STD = -std=gnu++11

ようは、g++ となっている部分を、g++-5 と変更します。なお、RMeCabのインストールが終わったら、また g++ を使うように戻しておきます。他に、''alternatives'' の仕組みを使って、''g++'' コマンドが参照するバージョンを変えて対応する方法もあるようです。
RMeCabがインストールできたら、いくつかの条件でRcppMeCabと比較をしてみましょう。

パッケージが提供する関数の種類

前述のように、RcppMeCabは pos() 関数および posParallel() 関数の2つしか提供しません。役割も、文字列ベクトルを与えたら、それを形態素解析して返す、というだけです。

一方、RMeCabは目的や入力の種類に応じて、様々な関数を提供しています。なお、以下はRMeCabパッケージのヘルプから関数名をリストアップし、説明を要約したものです。すべての関数が正常に利用できるかは検証していません。また、おそらく歴史的な経緯により、同じような機能を持った関数が複数提供されています。

  • collocate: 共起頻度を抽出する
  • collScores: 共起頻度からT値とMI値を算出する
  • coOccurrence: 共起行列 (Co-occurrence term matrix) を作成する
  • docDF: RMeCabの様々な関数の裏で使われている基本となる関数。フォルダーパス、ファイル名、データフレームを与えると、形態素解析してnグラム (デフォルトはユニグラム) のデータフレームを返す
  • docMatrix: 文書単語 (ターム・文書) 行列 (Document term matrix) を作成する
  • docMatrix2: 通常は使用しないとのこと
  • docMatrixDF: データフレームの指定列を対象に文書単語 (ターム・文書) 行列 (Document term matrix) を作成する
  • docNgram: 指定したフォルダー内の文書からnグラムを算出し、データフレームで返す
  • docNgram2: 指定したフォルダー内の文書からnグラムを算出し、データフレームで返す。docNgram() 関数との違いは minFreq オプションが指定できること
  • docNgramDF: データフレームの指定列を対象にnグラムを算出し、データフレームで返す
  • docVector: docMatrix() 関数のベクトル版。文書を1つだけ与えると、形態素と頻度のセットが返ってくる
  • entropy: 文書単語 (ターム・文書) 行列 (Document term matrix) を与えると、重要度などで重みをかけた行列を返す (詳細は省略)
  • globalEntropy: 同上
  • globalIDF: 同上
  • globalIDF2: 同上
  • globalIDF3: 同上
  • globalNorm: 同上
  • localBin: 同上
  • localLogTF: 同上
  • localTF: 同上
  • makeNgram: 指定した文書 (ファイル) からnグラムを算出し、データフレームで返す
  • mynorm: 文書単語 (ターム・文書) 行列 (Document term matrix) を与えると、重要度などで重みをかけた行列を返す (詳細は省略)
  • Ngram: 指定した文書 (ファイル) からnグラムを算出し、データフレームで返す
  • NgramDF: 指定した文書 (ファイル) からnグラムを算出し、データフレームで返す。Ngram() 関数との違いはnグラムの各語が列に分かれて返ってくること
  • NgramDF2: 指定した文書 (ファイル) からnグラムを算出し、データフレームで返す。NgramDF() 関数との違いは minFreq オプションが指定できること
  • print.docMatrix: 文書単語 (ターム・文書) 行列 (Document term matrix) を出力 (画面表示) する
  • removeInfo: 文書単語 (ターム・文書) 行列 (Document term matrix) から余分な出力を取り除く
  • RMeCabC: 文字列ベクトルを対象に形態素解析を行い、結果をリストで返す
  • RMeCabDF: データフレームの指定列を対象に形態素解析を行い、結果をデータフレームで返す
  • RMeCabDoc: 指定した文書 (ファイル) を対象に形態素解析を行い、結果をリストで返す
  • RMeCabFreq: 指定した文書 (ファイル) を対象に形態素解析および頻度集計を行い、結果をデータフレームで返す
  • RMeCabMx: 指定した文書 (ファイル) を対象に形態素解析を行い、結果をリストで返す。RMeCabDoc() 関数との違いは、pos オプションなどで処理対象 (品詞の種類) を指定できること
  • RMeCabText: 指定した文書 (ファイル) を対象に形態素解析を行い、結果をリストで返す
  • rmSign: 形態素解析の結果 (リスト) から記号に区分される文字を取り除く (MeCabの品詞情報ではなく、文字コードを指定している様子)

提供する関数の種類からも、RMeCabはテキストマイニングにおける一般的な処理を、パッケージ単体で実行できます。一方、RcppMeCabは形態素解析をするだけですので、nグラムや文書単語 (ターム・文書) 行列 (Document term matrix) を作成するには、tidyverseパッケージ群や後述のtidytextパッケージを組み合わせる必要があります。

処理速度の比較

次に、大量 (ファイルサイズ、ファイル数) のテキストデータを処理する際の性能について比較してみます。なお、ここからはLinuxでの実行結果を掲載しています。[1]Windowsでも、ほぼ同じ結果になるはずです。

 ファイルサイズが小さい場合

ファイルサイズがさほど大きくないテキストを読み込み、形態素解析の速度を比較します。ここでは、2018年10月24日に行われた第百九十七回国会における安倍内閣総理大臣所信表明演説を使用します。[2]ファイルは19KB前後、19152文字です。

速度のベンチマークには、microbenchmarkパッケージを使います。完全に同一のアウトプットにはなりませんが、おおよそ同じような結果が得られる処理にかかる実行時間を計測します。

library(tidyverse)
library(RMeCab)
library(RcppMeCab)
library(microbenchmark)
url <- "https://raw.githubusercontent.com/ltl-manabi/R/master/RcppMeCab_example/prime_minister_speech_20181024.txt"
download.file(url, destfile = "prime_minister_speech_20181024.txt")
# ベンチマークの設定、実行
# ファイルI/Oが影響しているか調べるため、あらかじめ読み込んでおく
df <- data.frame(speech=readLines("prime_minister_speech_20181024.txt"), stringsAsFactors = FALSE)
vec <- readLines("prime_minister_speech_20181024.txt")
mbr <- microbenchmark("RMeCab" = {res_rmecab <- docDF("prime_minister_speech_20181024.txt", type = 1, N = 1)},
                      "RMeCab (df)" = {res_rmecab_df <- docDF(df, col = 1, type = 1, N = 1)},
                      "RcppMeCab" = {res_rcppmecab <- readLines("prime_minister_speech_20181024.txt") %>%
                                     pos(., format = "data.frame") %>%
                                     group_by(base, pos, subtype) %>% summarise(count = n())},
                      "RcppMeCab (vec)" = {res_rcppmecab_vec <- vec %>% pos(., format = "data.frame") %>%
                                     group_by(base, pos, subtype) %>% summarise(count = n())},
                      "RcppMeCab (parallel)" = {res_rcppmecab_parallel <- vec %>% posParallel(., format = "data.frame") %>%
                                     group_by(base, pos, subtype) %>% summarise(count = n())},
                     times = 10)
ggplot(mbr, aes(x = expr, y = time * 1e-9, fill = expr)) +
stat_summary(fun.y = mean, geom = "bar", na.rm = TRUE) +
labs(title = "RMeCabとRcppMeCabの実行速度 比較", x = "", y = "実行時間 (秒)") +
theme_bw(base_size = 14) + theme(legend.position = "none")
ggsave("rmecab_rcppmecab_compare01.png", width = 8, height = 6)

結果を見ると、RcppMeCabの処理が圧倒的に高速であることがわかります。念のため、ファイルI/Oが影響するかを見るためにあらかじめデータフレーム、ベクトルに読み込んだ場合の処理も比較していますが、都度ファイルを読み込む場合と、筆者の環境ではほとんど差はありません。なお、RcppMeCabにおいては、pos() 関数と posParallel() 関数の差は大きくなく、むしろ posParallel() 関数のほうがやや遅いという結果になりました。

 ファイルサイズが大きい場合

(といっても、本格的に大きいファイルはベンチマーク環境を用意するのも大変なので、あくまで相対的に、というものです)

ここでは、2018年7月20日に行われた第196回通常国会 本会議議事録より枝野幸男議員の演説部分を抜粋して使用します。[3]ファイルは140KB程度、143722文字です。コードはほぼ同様です。

library(tidyverse)
library(RMeCab)
library(RcppMeCab)
library(microbenchmark)
#url <- "https://raw.githubusercontent.com/ltl-manabi/R/master/RcppMeCab_example/diet_speech_20180720.txt"
#download.file(url, destfile = "diet_speech_20180720.txt")
# ベンチマークの設定、実行
# ファイルI/Oが影響しているか調べるため、あらかじめ読み込んでおく
df <- data.frame(speech=readLines("diet_speech_20180720.txt"), stringsAsFactors = FALSE)
vec <- readLines("diet_speech_20180720.txt")
mbr <- microbenchmark("RMeCab" = {res_rmecab <- docDF("diet_speech_20180720.txt", type = 1, N = 1, Genkei = 1)},
                      "RMeCab (df)" = {res_rmecab_df <- docDF(df, col = 1, type = 1, N = 1, Genkei = 1)},
                      "RcppMeCab" = {res_rcppmecab <- readLines("diet_speech_20180720.txt") %>%
                                     pos(., format = "data.frame") %>%
                                     group_by(base, pos, subtype) %>% summarise(count = n())},
                      "RcppMeCab (vec)" = {res_rcppmecab_vec <- vec %>% pos(., format = "data.frame") %>%
                                     group_by(base, pos, subtype) %>% summarise(count = n())},
                      "RcppMeCab (parallel)" = {res_rcppmecab_parallel <- vec %>% posParallel(., format = "data.frame") %>%
                                     group_by(base, pos, subtype) %>% summarise(count = n())},
                     times = 10)
ggplot(mbr, aes(x = expr, y = time * 1e-9, fill = expr)) +
stat_summary(fun.y = mean, geom = "bar", na.rm = TRUE) +
labs(title = "RMeCabとRcppMeCabの実行速度 比較", x = "", y = "実行時間 (秒)") +
theme_bw(base_size = 14) + theme(legend.position = "none")
ggsave("rmecab_rcppmecab_compare02.png", width = 8, height = 6)

今度は、RMeCabのほうが速いという結果になりました。原因は不明ですが、RcppMeCabはコードが不安定な部分もあり、パフォーマンスチューニングができていないのかもしれません。なお、posParallel() 関数に続くdplyrの処理が遅いのかもしれない、と削ったケースも計測しましたが、結果はほとんど変わりませんでした。

NEologd辞書との相性についての比較

次に、2つのパッケージとNEologd辞書との相性について比較します。形態素解析器MeCabのページで取り上げた例文を再度示します。

May J.がmacOSを搭載したMacBook ProをAir DOの機内に持ち込んだ。

このセンテンスをMeCab + NEologd辞書で形態素解析すると、以下のようになります。

May J.  名詞,固有名詞,人名,一般,*,*,May J.,メイジェイ,メイジェイ
が      助詞,格助詞,一般,*,*,*,が,ガ,ガ
macOS   名詞,固有名詞,一般,*,*,*,macOS,マックオーエス,マックオーエス
を      助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
搭載    名詞,サ変接続,*,*,*,*,搭載,トウサイ,トーサイ
し      動詞,自立,*,*,サ変・スル,連用形,する,シ,シ
た      助動詞,*,*,*,特殊・タ,基本形,た,タ,タ
MacBook Pro     名詞,固有名詞,一般,*,*,*,MacBook Pro,マックブックプロ,マックブックプロ
を      助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
Air DO  名詞,固有名詞,一般,*,*,*,Air DO,エアドゥ,エアドゥ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
機内    名詞,一般,*,*,*,*,機内,キナイ,キナイ
に      助詞,格助詞,一般,*,*,*,に,ニ,ニ
持ち込ん        動詞,自立,*,*,五段・マ行,連用タ接続,持ち込む,モチコン,モチコン
だ      助動詞,*,*,*,特殊・タ,基本形,だ,ダ,ダ
。      記号,句点,*,*,*,*,。,。,。
EOS

結果を見ると、"May J." や "MacBook Pro" など、出現形および原形にスペースが含まれます。実は、RMeCabは (関数によっては) このようなスペースを含む形態素 (出現形、原形) を正しく処理できません。実際に、RMeCabの docDF() 関数および RMeCabFreq() 関数で処理してみましょう。

library(RMeCab)
df <- data.frame(text = "May J.がmacOSを搭載したMacBook ProをAir DOの機内に持ち込んだ。", stringsAsFactors = FALSE)
docDF(df, col = 1, type = 1, N = 1, Genkei = 1)
number of extracted terms = 15
now making a data frame. wait a while!
 docDF(df, col = 1, type = 1, N = 1, Genkei = 1) でエラー:
  SET_STRING_ELT() can only be applied to a 'character vector', not a 'integer'

file <- tempfile()
writeLines("May J.がmacOSを搭載したMacBook ProをAir DOの機内に持ち込んだ。", file)
readLines(file)
[1] "May J.がmacOSを搭載したMacBook ProをAir DOの機内に持ち込んだ。"
RMeCabFreq(file)
file = /tmp/Rtmp6dIFLM/file27814e582f3
length = 15
       Term  Info1    Info2 Freq
1        た 助動詞        *    1
2        だ 助動詞        *    1
3        が   助詞   格助詞    1
4        に   助詞   格助詞    1
5        を   助詞   格助詞    2
6        の   助詞   連体化    1
7      する   動詞     自立    1
8  持ち込む   動詞     自立    1
9      搭載   名詞 サ変接続    1
10     機内   名詞     一般    1
11      Air   名詞 固有名詞    1
12  MacBook   名詞 固有名詞    1
13      May   名詞 固有名詞    1
14    macOS   名詞 固有名詞    1
15       。   記号     句点    1

docDF() 関数ではエラーになります。また、RMeCabFreq() 関数では、エラーにはならないものの、" J." や " Pro" など形態素の一部が無視されています。これは、MeCabに付属するIPA辞書が、スペースを含む形態素を規定しておらず、RMeCabはそれに沿って実装されたためです。[4]一方で、RcppMeCabではスペースを含む形態素も正常に処理できます。

library(RcppMeCab)
pos("May J.がmacOSを搭載したMacBook ProをAir DOの機内に持ち込んだ。", format = "data.frame")
   doc_id sentence_id token_id       token    pos  subtype        base             yomi
1       1           1        1      May J.   名詞 固有名詞      May J.       メイジェイ
2       1           1        2          が   助詞   格助詞          が               ガ
3       1           1        3       macOS   名詞 固有名詞       macOS   マックオーエス
4       1           1        4          を   助詞   格助詞          を               ヲ
5       1           1        5        搭載   名詞 サ変接続        搭載         トウサイ
6       1           1        6          し   動詞     自立        する               シ
7       1           1        7          た 助動詞                   た               タ
8       1           1        8 MacBook Pro   名詞 固有名詞 MacBook Pro マックブックプロ
9       1           1        9          を   助詞   格助詞          を               ヲ
10      1           1       10      Air DO   名詞 固有名詞      Air DO         エアドゥ
11      1           1       11          の   助詞   連体化          の               ノ
12      1           1       12        機内   名詞     一般        機内           キナイ
13      1           1       13          に   助詞   格助詞          に               ニ
14      1           1       14    持ち込ん   動詞     自立    持ち込む         モチコン
15      1           1       15          だ 助動詞                   だ               ダ
16      1           1       16          。   記号     句点          。               。

現在では、NEologd辞書なしでのテキストマイニングは困難です。そのため、今後はRcppMeCabを使用することを推奨します。[5]

ここまで、RMeCabパッケージとRcppMeCabパッケージの性能や動作の違いを比較しました。


  • [1]2つのOSで同じことをやるのも面倒なので…。
  • [2]何も政治的な意図はないですが、自由に使ってよいので。
  • [3]何も政治的な意図はないですが、「演説 長い」で検索したら出てきたので。
  • [4]そのため、バグというよりは仕様と言えます。
  • [5]個人の意見です。

関連ページ: R言語を学ぶための参考書籍リスト
カテゴリ: [R,データ分析,テキストマイニング,RcppMeCabとtidytextではじめるテキストマイニング]