RserveをC++から使ってみる

最近Rを使っていなさすぎて死ぬレベルなので、Rを使うことにした。ただし、C++を通して。

RserveというRを叩けるTCP/IPサーバーがあるらしいので、それを使います。主にJavaで使うことを想定されているらしいですが、Javaはもう覚えていないので*1、C++で触ります。

まずはおもむろにインストール。

install.packages("Rserve")
library(Rserve)

マニュアルを読んでいると

R CMD Rserve

でいけるとあるのだけれど、それではうまく起動しなかったので

R CMD /Library/Frameworks/R.framework/Resources/library/Rserve/libs/i386/Rserve.so  

とやるとうまくいった。で、色々読んでいるとC++のクライアントの例が付属されているよーとのことだったので、それをやってみます。Rserve/src/client/cxxに移動して、configure && make。さっきのサーバーを起動した状態で動かすことができます。こんな感じ。

/Users/syou6162/Downloads/Rserve/src/client/cxx% ./demo1 
Rdouble[4]
33.97 -2.1 -2.1 10.09 
3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 3.7 3.4 3 3 4 4.4 3.9 3.5 3.8 3.8 3.4 3.7 3.6 3.3 3.4 3 3.4 3.5 3.4 3.2 3.1 3.4 4.1 4.2 3.1 3.2 3.5 3.6 3 3.4 3.5 2.3 3.2 3.5 3.8 3 3.8 3.2 3.7 3.3 3.2 3.2 3.1 2.3 2.8 2.8 3.3 2.4 2.9 2.7 2 3 2.2 2.9 2.9 3.1 3 2.7 2.2 2.5 3.2 2.8 2.5 2.8 2.9 3 2.8 3 2.9 2.6 2.4 2.4 2.7 2.7 3 3.4 3.1 2.3 3 2.5 2.6 3 2.6 2.3 2.7 3 2.9 2.9 2.5 2.8 3.3 2.7 3 2.9 3 3 2.5 2.9 2.5 3.6 3.2 2.7 3 2.5 2.8 3.2 3 3.8 2.6 2.2 3.2 2.8 2.8 2.7 3.3 3.2 2.8 3 2.8 3 2.8 3.8 2.8 2.8 2.6 3 3.4 3.1 3 3.1 3.1 3.1 2.7 3.2 3.3 3 2.5 3 3.4 3 

わーい。

用意されているデモだけでは面白くないので、自分でなんか例を書いてみた。library(e1071)にはナイーブベイズの関数があるようなので、C++側からその関数を呼んで学習、予測という流れをやってみた。

#include <iostream>

#define MAIN
#define SOCK_ERRORS

#include "sisocks.h"
#include "Rconnection.h"

int main(int argc, char **argv) {
  using namespace std;
  initsocks(); // this is needed for Win32 - it does nothing on unix
  Rconnection *rc = new Rconnection();
    
  int i=rc->connect();
  if (i) {
	char msg[128];
	sockerrorchecks(msg, 128, -1);
	printf("unable to connect (result=%d, socket:%s).\n", i, msg); return i;
  }
   
  rc->eval("library(mlbench)");
  rc->eval("library(e1071)");
  rc->eval("data(HouseVotes84, package=\"mlbench\")");
  rc->eval("model <- naiveBayes(Class ~ ., data = HouseVotes84)");
  Rstrings *predict = (Rstrings*) rc->eval("as.character(predict(model, HouseVotes84[1:10,-1]))");

  {
	int i = 0, ct = predict->length();
	while (i < ct) { cout << predict->stringAt(i++) << endl; }
  }
  delete predict;

  delete rc;
}

実行結果。

/Users/syou6162/Downloads/Rserve/src/client/cxx% ./example
 要求されたパッケージ class をロード中です 
republican
republican
republican
democrat
democrat
democrat
republican
republican
republican
democrat

ReadMe.txtを読んだりすれば分かるけど、Javaに比べるとC++側は最低限のところまでしか実装してないみたい。Java側には

  • 論理型ベクトル
  • 因子型
  • S4

などなどが用意されてあるが、C++ではそれらが用意されていない。なんでも作者がC++のほうは使わないからだとか。

参考

*1:本当のことを言うとJavaでの開発環境を整えるのが面倒w