RcppKagomeは、Rで形態素解析するためのパッケージです。Pure Goで辞書同梱な形態素解析器として知られるikawaha/kagomeをラップしています。
remotes::install_github(
"paithiov909/RcppKagome"
#, INSTALL_opts = "--no-multiarch" # for windows user
)
なお、ソースパッケージからビルドするため、インストールにはSystem Requirementsにあげられているものが必要です。
character vectorを渡せます。戻り値はリストです。
res <- RcppKagome::kagome("雨にも負けず 風にも負けず")
str(res)
#> List of 1
#> $ :List of 11
#> ..$ 0 :List of 5
#> .. ..$ Id : int 376225
#> .. ..$ Start : int 0
#> .. ..$ End : int 1
#> .. ..$ Surface: chr "雨"
#> .. ..$ Feature: chr [1:9] "名詞" "一般" "*" "*" ...
#> ..$ 1 :List of 5
#> .. ..$ Id : int 53040
#> .. ..$ Start : int 1
#> .. ..$ End : int 2
#> .. ..$ Surface: chr "に"
#> .. ..$ Feature: chr [1:9] "助詞" "格助詞" "一般" "*" ...
#> ..$ 2 :List of 5
#> .. ..$ Id : int 73244
#> .. ..$ Start : int 2
#> .. ..$ End : int 3
#> .. ..$ Surface: chr "も"
#> .. ..$ Feature: chr [1:9] "助詞" "係助詞" "*" "*" ...
#> ..$ 3 :List of 5
#> .. ..$ Id : int 352000
#> .. ..$ Start : int 3
#> .. ..$ End : int 5
#> .. ..$ Surface: chr "負け"
#> .. ..$ Feature: chr [1:9] "動詞" "自立" "*" "*" ...
#> ..$ 4 :List of 5
#> .. ..$ Id : int 36553
#> .. ..$ Start : int 5
#> .. ..$ End : int 6
#> .. ..$ Surface: chr "ず"
#> .. ..$ Feature: chr [1:9] "助動詞" "*" "*" "*" ...
#> ..$ 5 :List of 5
#> .. ..$ Id : int 95
#> .. ..$ Start : int 6
#> .. ..$ End : int 7
#> .. ..$ Surface: chr " "
#> .. ..$ Feature: chr [1:9] "記号" "空白" "*" "*" ...
#> ..$ 6 :List of 5
#> .. ..$ Id : int 380203
#> .. ..$ Start : int 7
#> .. ..$ End : int 8
#> .. ..$ Surface: chr "風"
#> .. ..$ Feature: chr [1:9] "名詞" "一般" "*" "*" ...
#> ..$ 7 :List of 5
#> .. ..$ Id : int 53040
#> .. ..$ Start : int 8
#> .. ..$ End : int 9
#> .. ..$ Surface: chr "に"
#> .. ..$ Feature: chr [1:9] "助詞" "格助詞" "一般" "*" ...
#> ..$ 8 :List of 5
#> .. ..$ Id : int 73244
#> .. ..$ Start : int 9
#> .. ..$ End : int 10
#> .. ..$ Surface: chr "も"
#> .. ..$ Feature: chr [1:9] "助詞" "係助詞" "*" "*" ...
#> ..$ 9 :List of 5
#> .. ..$ Id : int 352000
#> .. ..$ Start : int 10
#> .. ..$ End : int 12
#> .. ..$ Surface: chr "負け"
#> .. ..$ Feature: chr [1:9] "動詞" "自立" "*" "*" ...
#> ..$ 10:List of 5
#> .. ..$ Id : int 36553
#> .. ..$ Start : int 12
#> .. ..$ End : int 13
#> .. ..$ Surface: chr "ず"
#> .. ..$ Feature: chr [1:9] "助動詞" "*" "*" "*" ...
結果をデータフレームに整形できます。
res <- RcppKagome::kagome(
c("陽が照って鳥が啼き あちこちの楢の林も、けむるとき",
"ぎちぎちと鳴る 汚い掌を、おれはこれからもつことになる"))
res <- RcppKagome::prettify(res)
print(res)
#> doc_id token POS1 POS2 POS3 POS4 X5StageUse1 X5StageUse2
#> 1 1 陽 名詞 一般 <NA> <NA> <NA> <NA>
#> 2 1 が 助詞 格助詞 一般 <NA> <NA> <NA>
#> 3 1 照っ 動詞 自立 <NA> <NA> 五段・ラ行 連用タ接続
#> 4 1 て 助詞 接続助詞 <NA> <NA> <NA> <NA>
#> 5 1 鳥 名詞 一般 <NA> <NA> <NA> <NA>
#> 6 1 が 助詞 格助詞 一般 <NA> <NA> <NA>
#> 7 1 啼き 動詞 自立 <NA> <NA> 五段・カ行イ音便 連用形
#> 8 1 記号 空白 <NA> <NA> <NA> <NA>
#> 9 1 あちこち 名詞 代名詞 一般 <NA> <NA> <NA>
#> 10 1 の 助詞 連体化 <NA> <NA> <NA> <NA>
#> 11 1 楢 名詞 一般 <NA> <NA> <NA> <NA>
#> 12 1 の 助詞 連体化 <NA> <NA> <NA> <NA>
#> 13 1 林 名詞 一般 <NA> <NA> <NA> <NA>
#> 14 1 も 助詞 係助詞 <NA> <NA> <NA> <NA>
#> 15 1 、 記号 読点 <NA> <NA> <NA> <NA>
#> 16 1 けむる 動詞 自立 <NA> <NA> 五段・ラ行 基本形
#> 17 1 とき 名詞 非自立 副詞可能 <NA> <NA> <NA>
#> 18 2 ぎちぎち 副詞 一般 <NA> <NA> <NA> <NA>
#> 19 2 と 助詞 格助詞 一般 <NA> <NA> <NA>
#> 20 2 鳴る 動詞 自立 <NA> <NA> 五段・ラ行 基本形
#> 21 2 記号 空白 <NA> <NA> <NA> <NA>
#> 22 2 汚い 形容詞 自立 <NA> <NA> 形容詞・アウオ段 基本形
#> 23 2 掌 名詞 一般 <NA> <NA> <NA> <NA>
#> 24 2 を 助詞 格助詞 一般 <NA> <NA> <NA>
#> 25 2 、 記号 読点 <NA> <NA> <NA> <NA>
#> 26 2 おれ 名詞 代名詞 一般 <NA> <NA> <NA>
#> 27 2 は 助詞 係助詞 <NA> <NA> <NA> <NA>
#> 28 2 これから 副詞 助詞類接続 <NA> <NA> <NA> <NA>
#> 29 2 もつ 動詞 自立 <NA> <NA> 五段・タ行 基本形
#> 30 2 こと 名詞 非自立 一般 <NA> <NA> <NA>
#> 31 2 に 助詞 格助詞 一般 <NA> <NA> <NA>
#> 32 2 なる 動詞 自立 <NA> <NA> 五段・ラ行 基本形
#> Original Yomi1 Yomi2
#> 1 陽 ヒ ヒ
#> 2 が ガ ガ
#> 3 照る テッ テッ
#> 4 て テ テ
#> 5 鳥 トリ トリ
#> 6 が ガ ガ
#> 7 啼く ナキ ナキ
#> 8
#> 9 あちこち アチコチ アチコチ
#> 10 の ノ ノ
#> 11 楢 ナラ ナラ
#> 12 の ノ ノ
#> 13 林 ハヤシ ハヤシ
#> 14 も モ モ
#> 15 、 、 、
#> 16 けむる ケムル ケムル
#> 17 とき トキ トキ
#> 18 ぎちぎち ギチギチ ギチギチ
#> 19 と ト ト
#> 20 鳴る ナル ナル
#> 21
#> 22 汚い キタナイ キタナイ
#> 23 掌 タナゴコロ タナゴコロ
#> 24 を ヲ ヲ
#> 25 、 、 、
#> 26 おれ オレ オレ
#> 27 は ハ ワ
#> 28 これから コレカラ コレカラ
#> 29 もつ モツ モツ
#> 30 こと コト コト
#> 31 に ニ ニ
#> 32 なる ナル ナル
整形されたデータフレームは次のカラムからなります。
このうちtoken列だけを半角スペースでcollapseして返す(分かち書きにする)ことができます。
RcppKagome::pack_df(res)
#> doc_id text
#> 1 1 陽 が 照っ て 鳥 が 啼き あちこち の 楢 の 林 も 、 けむる とき
#> 2 2 ぎちぎち と 鳴る 汚い 掌 を 、 おれ は これから もつ こと に なる
なお、prettify
を経由しなくても同じかたちのデータフレームを得ることができます。
RcppMeCabと速度比較しています。
単文の解析速度としてはとくに遅いということはないはずです。
このグラフからだとやや遅く見えるかもしれませんが、同じ実行環境でspacyrを用いてPOS tagging(’ja_core_news_md’モデルを使用、spacyr::spacy_parse(lemma = FALSE, entity = FALSE, mutlithread = TRUE)
)すると、平均で90ms程度かかります。sapCyはUniversal Dependenciesを扱うライブラリであってそもそも「形態素解析」をする実装ではないのですが、あえて比較するならば、RcppKagomeでも明らかに速いです。
ベクトル(2258 elements, 1.1MB)を渡す場合、ふつうに使うかぎりではRcppMeCabが速いと思われます。
このような結果になる理由として、RcppMeCabはC++のレベルでvectorizeされているという点があります。RcppMeCab::pos
はMeCabのタガーインスタンスを一つだけつくってそれぞれの文をひとつずつ解析する処理を繰り返します。一方で、RcppMeCab::posParallel
はマルチスレッドで、スレッドごとにMeCabのタガーインスタンスを生成します。いずれにせよ、RcppMeCabではベクトルを与えられた場合、各文の解析に用いるタガーを内部的に使いまわしています。形態素解析をするライブラリでは一般にタガーインスタンスの生成はコストが高い処理であるため、解析の際にタガーの生成が繰り返されるとそれがボトルネックになって、解析に時間がかかります(これはRcppMeCabだけについてみても同様で、たとえばスレッドごとに処理する文の分量が極端に少ない場合、個々の文の解析にかかる時間の割にインスタンスの生成にコストが割かれることになって、RcppMeCab::pos
よりRcppMeCab::posParallel
のほうがかえってパフォーマンスが悪化することがあります)。
RMeCabやRcppKagomeでは解析するたびごとにタガーの生成を繰り返す必要があるため、実用上はおそらくRcppMeCabに比べて遅くなります。
なお、この記事の主旨から外れますが、これくらいの分量のベクトルをspacyrで解析しようとすると結果をデータフレームにパースするコストが高すぎて死ぬほど時間がかかるので、そういう使い方は避けたほうがよいです。
日本語情報としては以下の記事があります。
この記事はもともとRomain Francois氏(RcppとかrJavaとかの開発にかかわっているスゴい人らしい)が書いたブログ記事を参考にしているものです。
Goにはcgo
というコマンドが用意されていて、Goで書かれたコードをC言語から利用するためのライブラリにすることができます。この機能を利用して生成したC言語向けのライブラリをRパッケージから呼び出すことで、いちおうはGoの資産をRから利用することができます。
本来、Cなどで書かれた関数をRパッケージで直接呼ぶためには.Call
を使って呼べる状態にするために関数のregistration
という操作が必要になります。この手間を省略するために、RcppKagomeではcgoで生成したライブラリをC++から利用するラッパーを書いて、それをRcppでエクスポートしています。
また、より便利に扱うためにはGoとのあいだに型マッピングを定義するのが望ましいのでしょうが、RcppKagomeではその点については深入りせず、文字列だけを受け渡しするようにしています。参考までに、Goとのあいだに型マッピングが定義されているほかの例を挙げておきます。
sessioninfo::session_info()
#> ─ Session info ──────────────────────────────────────────────────────────────
#> hash: index pointing up, fork and knife, index pointing up: light skin tone
#>
#> setting value
#> version R version 4.1.2 (2021-11-01)
#> os Ubuntu 20.04.3 LTS
#> system x86_64, linux-gnu
#> ui X11
#> language (EN)
#> collate C.UTF-8
#> ctype C.UTF-8
#> tz UTC
#> date 2021-11-14
#> pandoc 2.7.3 @ /usr/bin/ (via rmarkdown)
#>
#> ─ Packages ───────────────────────────────────────────────────────────────────
#> package * version date (UTC) lib source
#> cachem 1.0.6 2021-08-19 [1] Custom
#> cli 3.1.0 2021-10-27 [1] Custom
#> crayon 1.4.2 2021-10-29 [1] Custom
#> desc 1.4.0 2021-09-28 [1] Custom
#> digest 0.6.28 2021-09-23 [1] Custom
#> dplyr 1.0.7 2021-06-18 [1] Custom
#> ellipsis 0.3.2 2021-04-29 [1] Custom
#> evaluate 0.14 2019-05-28 [1] Custom
#> fansi 0.5.0 2021-05-25 [1] Custom
#> fastmap 1.1.0 2021-01-25 [1] Custom
#> fs 1.5.0 2020-07-31 [1] Custom
#> generics 0.1.1 2021-10-25 [1] Custom
#> glue 1.5.0 2021-11-07 [1] Custom
#> htmltools 0.5.2 2021-08-25 [1] Custom
#> jsonlite 1.7.2 2020-12-09 [1] Custom
#> knitr 1.36 2021-09-29 [1] Custom
#> lifecycle 1.0.1 2021-09-24 [1] Custom
#> magrittr 2.0.1 2020-11-17 [1] Custom
#> memoise 2.0.0 2021-01-26 [1] Custom
#> pillar 1.6.4 2021-10-18 [1] Custom
#> pkgconfig 2.0.3 2019-09-22 [1] Custom
#> pkgdown 1.6.1 2020-09-12 [1] Custom
#> purrr 0.3.4 2020-04-17 [1] Custom
#> R6 2.5.1 2021-08-19 [1] Custom
#> ragg 1.2.0 2021-10-30 [1] Custom
#> Rcpp 1.0.7 2021-07-07 [1] Custom
#> RcppKagome 0.1.1 2021-11-14 [1] local
#> RcppParallel 5.1.4 2021-05-04 [1] Custom
#> rlang 0.4.12 2021-10-18 [1] Custom
#> rmarkdown 2.11 2021-09-14 [1] Custom
#> rprojroot 2.0.2 2020-11-15 [1] Custom
#> sessioninfo 1.2.1 2021-11-02 [1] Custom
#> stringi 1.7.5 2021-10-04 [1] Custom
#> stringr 1.4.0 2019-02-10 [1] Custom
#> systemfonts 1.0.3 2021-10-13 [1] Custom
#> textshaping 0.3.6 2021-10-13 [1] Custom
#> tibble 3.1.6 2021-11-07 [1] Custom
#> tidyselect 1.1.1 2021-04-30 [1] Custom
#> utf8 1.2.2 2021-07-24 [1] Custom
#> vctrs 0.3.8 2021-04-29 [1] Custom
#> xfun 0.28 2021-11-04 [1] Custom
#> yaml 2.2.1 2020-02-01 [1] Custom
#>
#> [1] /home/runner/work/_temp/Library
#> [2] /opt/R/4.1.2/lib/R/library
#>
#> ──────────────────────────────────────────────────────────────────────────────