データサイエンスワールドから
C++を眺めてみる
2014年3⽉1⽇
Boost.勉強会#14
@sfchaos
⾃⼰紹介

 TwitterID:@sfchaos
 お仕事:データマイニング
 普段の使⽤⾔語:R,Python,Perl,シェル

1
アジェンダ
1.
2.
3.
4.

イントロダクション
RからC++を使ってみる
C++での統計解析
まとめ

2
1. イントロダクション

3
最近モテモテの
データサイエンティスト
出典:http://markezine.jp/article/detail/18435
4
データサイエンティストたちは
どんなツールを使っている?
5
1位 

2位 

3位 

C/C++は9位
Top Languages for analytics, data mining, data science
6
 データ分析では分析仕様が初めから決まっているとは限らず,
探索的に分析してデータの特徴を明らかにすることが重要.
 また,分析結果を分かりやすく可視化できる環境が必要.
 こうした観点から,RやPython等が分析ツールとして⽤いら
れることが多い.

7
RからPythonへの流れも??

データ・サイエンスのプログラミング⾔語はRからPythonに置き換わる
8
 ⼀⽅で,特にRは処理が遅い.
• ループ処理など

 そのため,RからC++を呼んで処理を⾼速化することは, 
結構よく⾏われる.
 また,C++からRの関数を呼び,統計処理を⾏わせる⽅法
もある.
 というわけで,今⽇は誰得?な話をします(^^;
9
2. RからC++を使ってみる

C++
10
2.1 Rcppパッケージ
 RからC++を実⾏するためのパッケージ.
 以下のような多くのライブラリとの連携機能も提供.
•
•
•
•

Eigen(線形代数演算)
GSL(科学技術計算)
Numpy(科学技術計算,Python)
Octave(科学技術計算) etc.

11
2.2 フィボナッチ数列
fibonatti.cpp

#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
int fibCpp(const int n) {
if (n < 2) {
return n;
} else {
return fibonacci(n-1) + fibonacci(n-2);
}
}
12
2.2 フィボナッチ数列
$ R
> install.packages("Rcpp")
> library(Rcpp)
> sourceCpp("fibCpp.cpp")
> fibCpp(20)
[1] 6765

13
2.2 フィボナッチ数列
 Rで実⾏した場合に⽐べて,約1,000倍のスピードアップ.
> sourceCpp("fibCpp.cpp")
> benchmark(fibCpp(20), fibR(20),
replications=5000)[, 1:4]
test replications elapsed relative
2
fibR(20)
5000 200.434 756.355
1 fibCpp(20)
5000
0.265
1.000
参考:@teramonagi
Tokyo.R ⽩熱教室「これからのRcppの話をしよう」

14
3. C++での統計解析

C++
15
3.1 C++での統計処理
 取り急ぎ調べたところ,以下のライブラリなどがある模様.
 良いライブラリがあったら教えてください(^^;
ライブラリ

記述統計量

統計的検定

多変量解析

機械学習

○

×

×

×

Apophenia

○

○

△

△

ROOT

△

△

△

△

GSL

△

×(?)

△

×(?)

ALGLIB

○

○

○

△

Boost.
Accumulators

○:多くの⼿法を提供 △:少数の⼿法を提供 ×:⾮提供
16
3.2 Boost.Accumulators
 統計量の計算などの統計処理を提供.
 最⼩値,平均値,中央値,最⼤値
 共分散
 密度
 合計値 等

 詳細は,BoostJpの逆引きリファレンスを参照.
  https://sites.google.com/site/boostjp/tips

17
3.2 Boost.Accumulators
 boost::accumulators::accumulator_setというコンテ
ナにデータを⼊⼒.
 テンプレートパラメータに実⾏する処理を指定(統計量計算)
#include <iostream>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>
using namespace boost::accumulators;
int main()
{
accumulator_set<double, stats<tag::min, tag::mean, tag::sum> > acc;
acc(3.0);
acc(1.0);
acc(4.0);
acc(2.0);
acc(5.0);

}

std::cout << extract::min(acc) << std::endl; // 最小値
std::cout << extract::mean(acc) << std::endl; // 平均値
std::cout << extract::sum(acc) << std::endl; // 合計値

18
3.2 Boost.Accumulators
 std::vectorや配列などのコンテナに格納されたデータに対し
ては,for_eachを使⽤してaccumulator_setに代⼊.
#include <iostream>
#include <boost/array.hpp>
#include <boost/range/algorithm/for_each.hpp>
#include
#include
#include
#include

<boost/bind.hpp>
<boost/ref.hpp>
<boost/accumulators/accumulators.hpp>
<boost/accumulators/statistics.hpp>

using namespace boost::accumulators;
int main()
{
int ar[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
accumulator_set<double, stats<tag::min, tag::mean, tag::max> > acc;
boost::for_each(ar, boost::bind(boost::ref(acc), _1));
std::cout << extract::min(acc) << std::endl; // 最小値
std::cout << extract::mean(acc) << std::endl; // 平均値
std::cout << extract::max(acc) << std::endl; // 最大値
}

return 0;

19
3.3 ALGLIB
 数値計算およびデータ処理のためのソフトウェア.
 C++, C#, Python, VBAなど多くのプログラミング⾔語から
呼び出せる.
 商⽤版もあり,マルチスレッドIntel Math Kernel Library
を⽤いた最適化・⾼速化等に対応

20
3.3 ALGLIB
#include <iostream>
#include "statistics.h"
using namespace std;
using namespace alglib;
int main()
{
real_1d_array x = "[0,1,4,9,16,25,36,49,64,81]";
real_1d_array y = "[0,1,2,3,4,5,6,7,8,9]";
double v;

ナゾの値の代⼊⽂

cout.precision(8);
// 共分散
v = cov2(x, y);
cout << "共分散: " << double(v) << endl;
// Pearson 相関係数
v = pearsoncorr2(x, y);
cout << "Pearson 相関係数: " << double(v) << endl;
// Spearman 相関係数
v = spearmancorr2(x, y);
cout << "Spearman 相関係数: " << double(v) << endl;
return 0;
}

21
3.4 C++からRの呼び出し
 RInsideというパッケージを⽤いることにより,C++からRを呼
び出せる.

22
3.4.1 式の評価
#include <RInside.h>
int main(int argc, char *argv[]) {
RInside R(argc, argv);
R["x"] = 10 ;
R["y"] = 20 ;

// C++に埋め込むRのインスタンスの⽣成
// Rのインスタンスにオブジェクトの名前と値を代⼊

R.parseEvalQ("z <- x + y") ;
// Rでの評価式
int sum = R["z"];
// []演算⼦でオブジェクトの値を取得
std::cout << "10 + 20 = " << sum << std::endl ;
// 以下の⽅法で評価してもO.K.
sum = R.parseEval("x + y") ;
std::cout << "10 + 20 = " << sum << std::endl ;
exit(0);
}
以下のRInlineパッケージのソースのinst/examples/standard/rinside_sample8.cpp
http://cran.r-project.org/src/contrib/RInside_0.2.11.tar.gz

23
Makefile

3.4.1 式の評価

## -*- mode: make; tab-width: 8; -*R_HOME :=
$(shell R RHOME)
sources :=
programs :=

$(wildcard *.cpp)
$(sources:.cpp=)

## Rのためのヘッダやライブラリ
RCPPFLAGS :=
$(shell $(R_HOME)/bin/R CMD config --cppflags)
RLDFLAGS :=
$(shell $(R_HOME)/bin/R CMD config --ldflags)
RBLAS :=
$(shell $(R_HOME)/bin/R CMD config BLAS_LIBS)
RLAPACK :=
$(shell $(R_HOME)/bin/R CMD config LAPACK_LIBS)
## Rcppのヘッダやライブラリ
RCPPINCL :=
$(shell echo 'library(Rcpp, lib.loc="/home/sfchaos/lib/R");Rcpp:::CxxFlags()' |
$(R_HOME)/bin/R --vanilla --slave)
RCPPLIBS :=
$(shell echo 'library(Rcpp, lib.loc="/home/sfchaos/lib/R");Rcpp:::LdFlags()' |
$(R_HOME)/bin/R --vanilla --slave)

## include headers and libraries for RInside embedding classes
RINSIDEINCL :=
$(shell echo 'library(RInside,
lib.loc="/home/sfchaos/lib/R");RInside:::CxxFlags()' | $(R_HOME)/bin/R --vanilla --slave)
RINSIDELIBS :=
$(shell echo 'library(RInside,
lib.loc="/home/sfchaos/lib/R");RInside:::LdFlags()' | $(R_HOME)/bin/R --vanilla --slave)

24
Makefile(続 )

3.4.1 式の評価

## makeするための各種のルール
CXX :=
$(shell $(R_HOME)/bin/R CMD config CXX)
CPPFLAGS :=
-Wall $(shell $(R_HOME)/bin/R CMD config CPPFLAGS)
CXXFLAGS :=
$(RCPPFLAGS) $(RCPPINCL) $(RINSIDEINCL) $(shell $(R_HOME)/bin/R CMD
config CXXFLAGS)
LDLIBS :=
$(RLDFLAGS) $(RRPATH) $(RBLAS) $(RLAPACK) $(RCPPLIBS) $(RINSIDELIBS)
all:

$(programs)
@test -x /usr/bin/strip && strip $^

run:

$(programs)
@for p in $(programs); do echo; echo "Running $$p:"; ./$$p; done

clean:
rm -vf $(programs)
rm -vrf *.dSYM
runAll:
for p in $(programs); do echo ""; echo ""; echo "Running $$p"; ./$$p; done

25
3.4.1 式の評価
$ make rinside_sample8.cpp
$ ./rinside_sample8
10 + 20 = 30
10 + 20 = 30

26
lm.cpp

3.4.2 回帰分析

#include <RInside.h>
int main(int argc, char *argv[])
{
RInside R(argc, argv); // C++ 埋 込 R

生成

std::vector<double> x;
x.push_back(1.0); x.push_back(2.0); x.push_back(3.0);
R["x"] = x;
std::vector<double> y;
y.push_back(2.0); y.push_back(4.0); y.push_back(6.0);
R["y"] = y;
// R 回帰分析 実行(y = 2*x)

R.parseEvalQ("fit.lm <- lm(y ~ x); fit.lm.coef <- fit.lm$coef");
std::vector<double> coef;
coef = R["fit.lm.coef"]; // 回帰係数 取得
std::cout << "傾 : " << coef[1] << std::endl;
std::cout << "切片: " << coef[0] << std::endl;

}

return 0;

27
3.4.2 回帰分析
$ make lm
g++ -I/usr/local/lib/R/include -I/home/sfchaos/lib/R/Rcpp/include I/home/sfchaos/lib/R/RInside/include -g -O2 -Wall I/usr/local/include
lm.cpp -L/usr/local/lib/R/lib -lR L/usr/local/lib/R/lib -lRblas -L/usr/local/lib/R/lib -lRlapack L/home/sfchaos/lib/R/RInside/lib -lRInside -Wl,rpath,/home/sfchaos/lib/R/RInside/lib -o lm
$ ./lm
傾き: 2
切⽚: -0

28
3.4.3 Qtへの埋め込み
 QtにRを埋め込むことも可能.
 詳細は以下を参照.
  R inside Qt: A simple RInside application

パラメータを変えて
計算を実⾏

29
4. まとめ

30
 R ⇔ C++の誰得な発表.
• R ⇒ C++: Rcpp
• C++ ⇒ R: RInside

 C++で統計解析を⾏うための良いツールがあれば,      
是⾮教えてください.

31

データサイエンスワールドからC++を眺めてみる