これは何?

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     なる       ナル       ナル

整形されたデータフレームは次のカラムからなります。

  • doc_id: 文番号(sentence index)
  • token: 表層形(surface form)
  • POS1~POS4: 品詞, 品詞細分類1, 品詞細分類2, 品詞細分類3
  • X5StageUse1: 活用型(ex. 五段, 下二段…)
  • X5StageUse2: 活用形(ex. 連用形, 終止形…)
  • Original: 原形(lemmatised form)
  • Yomi1: 読み(readings)
  • Yomi2: 発音(pronunciation)

このうちtoken列だけを半角スペースでcollapseして返す(分かち書きにする)ことができます。

RcppKagome::pack_df(res)
#>   doc_id                                                                 text
#> 1      1   陽 が 照っ て 鳥 が 啼き   あちこち の 楢 の 林 も 、 けむる とき
#> 2      2 ぎちぎち と 鳴る   汚い 掌 を 、 おれ は これから もつ こと に なる

なお、prettifyを経由しなくても同じかたちのデータフレームを得ることができます。

res <- RcppKagome::kagome("雨にも負けず 風にも負けず")
RcppKagome::pack_list(res)
#>   doc_id                                 text
#> 1      1 雨 に も 負け ず   風 に も 負け ず

速度比較

RcppMeCabと速度比較しています。

単文を渡す場合

単文の解析速度としてはとくに遅いということはないはずです。

bench-plot-1

このグラフからだとやや遅く見えるかもしれませんが、同じ実行環境で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が速いと思われます。

bench-plot-2

このような結果になる理由として、RcppMeCabはC++のレベルでvectorizeされているという点があります。RcppMeCab::posはMeCabのタガーインスタンスを一つだけつくってそれぞれの文をひとつずつ解析する処理を繰り返します。一方で、RcppMeCab::posParallelはマルチスレッドで、スレッドごとにMeCabのタガーインスタンスを生成します。いずれにせよ、RcppMeCabではベクトルを与えられた場合、各文の解析に用いるタガーを内部的に使いまわしています。形態素解析をするライブラリでは一般にタガーインスタンスの生成はコストが高い処理であるため、解析の際にタガーの生成が繰り返されるとそれがボトルネックになって、解析に時間がかかります(これはRcppMeCabだけについてみても同様で、たとえばスレッドごとに処理する文の分量が極端に少ない場合、個々の文の解析にかかる時間の割にインスタンスの生成にコストが割かれることになって、RcppMeCab::posよりRcppMeCab::posParallelのほうがかえってパフォーマンスが悪化することがあります)。

RMeCabやRcppKagomeでは解析するたびごとにタガーの生成を繰り返す必要があるため、実用上はおそらくRcppMeCabに比べて遅くなります。

なお、この記事の主旨から外れますが、これくらいの分量のベクトルをspacyrで解析しようとすると結果をデータフレームにパースするコストが高すぎて死ぬほど時間がかかるので、そういう使い方は避けたほうがよいです。

RとGoの連携について

日本語情報としては以下の記事があります。

この記事はもともと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
#> 
#> ──────────────────────────────────────────────────────────────────────────────