{Rcpp}によってNEologdを使う

  • 1
    いいね
  • 0
    コメント

概要

 RからMeCabを呼ぶときに辞書を変えるときのメモ。公式ページに{RMeCab}を利用する例がありますが、今回は{Rcpp}でラッパーを作ってNEologdを使います。

事前準備

 NEologdのインストールは、公開先のREADMEに記載してあるコードを実行しました。

Neologdインストール
$ git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git
$ cd mecab-ipadic-neologd
$ ./bin/install-mecab-ipadic-neologd -n

# 自分のMac環境だとインストール先は下記
$ echo `mecab-config --dicdir`"/mecab-ipadic-neologd"
/usr/local/Cellar/mecab/0.996/lib/mecab/dic/mecab-ipadic-neologd

定義・設定

{Rcpp}でラッパーを作成し、入出力用にRの関数を定義。

パッケージ読み込みと関数定義
library(Rcpp)
library(dplyr)
library(tidyr)

# ラッパー作成
Sys.setenv("PKG_LIBS" = "-lmecab")
callRcppMecab <- Rcpp::cppFunction(
  code = '
    Rcpp::DataFrame executeMecab(std::string str, std::string tagger_opt) {
    using namespace Rcpp;
    using namespace MeCab;

    std::vector<std::string> surface, feature;
    MeCab::Tagger *tagger = MeCab::createTagger(tagger_opt.c_str());
    const MeCab::Node *node(tagger->parseToNode(str.c_str()));
    for (; node; node = node->next) {
      if (node->stat != MECAB_BOS_NODE & node->stat != MECAB_EOS_NODE) {
        surface.push_back(std::string(node->surface, node->length));
        feature.push_back(std::string(node->feature));
      }
    }
    delete tagger;

    return Rcpp::wrap(
        Rcpp::DataFrame::create(
        Rcpp::Named("surface") = surface,
        Rcpp::Named("feature") = feature
      )
    );
  }',
  includes = c("#include <mecab.h>")
)

# 整形用関数
# 素性レベル(l)と辞書のパス(d)のみを指定
callMecab <- function (string, tagger_param = list(l = 2, d = NULL)) {
  if (length(x = tagger_param) > 0) {
    tagger_opt_str <- lapply(
      X = names(x = tagger_param),
      FUN = function (tg) {
        if (!is.null(x = tagger_param[[tg]]) & is.element(el = tg, set = c("l", "d"))) {
          return(
            stringr::str_c(stringr::str_c("-", tg), tagger_param[tg], sep = " ")
          )
        }
      }
    ) %>% 
      unlist %>% 
      stringr::str_c(collapse = " ")
  } else {
    tagger_opt_str <- ""    
  }

  return(
    callRcppMecab(str = as.character(x = string), tagger_opt = tagger_opt_str) %>% 
      tidyr::separate(
        col = feature, 
        into = c("pos", "pos1", "pos2", "pos3", "ctype", "cform", "baseform", "orth", "pron"),
        sep = ",", fill = "right"
      ) 
  )
}

実行例

# タガー用の引数を与えないときはデフォルト呼び出し
> callMecab(
  string = "すもももももももものうち",
  tagger_param = list()
)
  surface  pos   pos1     pos2 pos3 ctype cform baseform   orth   pron
1  すもも 名詞   一般        *    *     *     *   すもも スモモ スモモ
2      も 助詞 係助詞        *    *     *     *       も     モ     モ
3    もも 名詞   一般        *    *     *     *     もも   モモ   モモ
4      も 助詞 係助詞        *    *     *     *       も     モ     モ
5    もも 名詞   一般        *    *     *     *     もも   モモ   モモ
6      の 助詞 連体化        *    *     *     *       の     ノ     ノ
7    うち 名詞 非自立 副詞可能    *     *     *     うち   ウチ   ウチ

# NEologdのインストールパスを指定
> callMecab(
  string = "すもももももももものうち",
  tagger_param = list(
    d ="/usr/local/Cellar/mecab/0.996/lib/mecab/dic/mecab-ipadic-neologd"
  )
)
                   surface  pos     pos1 pos2 pos3 ctype cform                 baseform                     orth                     pron
1 すもももももももものうち 名詞 固有名詞 一般    *     *     * すもももももももものうち スモモモモモモモモノウチ スモモモモモモモモノウチ

 辞書を変えた結果が反映されています。

まとめ

 {Rcpp}でラッパーを作り、引数の切り替えによってNEologdを用いた形態素解析も実行できるようにしました。これにより、Rでのテキスト分析を様々な入力で試したくなるかと思います。
 長らく放置しているRでいろいろな形態素解析器を呼び出すライブラリの更新をそろそろしたいですが、Window対応からは逃げたいところです。

参考

実行環境

実行環境
> devtools::session_info()
Session info ----------------------------------------------------------------------------------------------------------------------------------
 setting  value                       
 version  R version 3.3.1 (2016-06-21)
 system   x86_64, darwin13.4.0        
 ui       RStudio (1.0.44)            
 language (EN)                        
 collate  ja_JP.UTF-8                 
 tz       Asia/Tokyo                  
 date     2016-11-04                  

Packages --------------------------------------------------------------------------------------------------------------------------------------
 package    * version date       source        
 assertthat   0.1     2013-12-06 CRAN (R 3.3.1)
 DBI          0.5     2016-08-11 cran (@0.5)   
 devtools     1.12.0  2016-06-24 CRAN (R 3.3.0)
 digest       0.6.9   2016-01-08 CRAN (R 3.3.0)
 dplyr      * 0.5.0   2016-06-24 CRAN (R 3.3.1)
 magrittr     1.5     2014-11-22 CRAN (R 3.3.1)
 memoise      1.0.0   2016-01-29 CRAN (R 3.3.0)
 R6           2.1.3   2016-08-19 cran (@2.1.3) 
 Rcpp       * 0.12.7  2016-09-05 cran (@0.12.7)
 stringi      1.1.1   2016-05-27 CRAN (R 3.3.1)
 stringr      1.1.0   2016-08-19 cran (@1.1.0) 
 tibble       1.2     2016-08-26 cran (@1.2)   
 tidyr      * 0.6.0   2016-08-12 cran (@0.6.0) 
 withr        1.0.2   2016-06-20 CRAN (R 3.3.0)