準備と動作確認 Preparation 〜RstudioでC++を覚える
- Rをインストール Install R
- Rstudioをインストール Install Rstudio
- RstudioのツールバーメニューからC++ファイルを新規作成、とすると、もしコンパイラとかの準備がまだだったらdevtoolsとかのインストールをするかどうか訊いてきてくれるので、それにしたがうのもよい
- Rstudioを立ち上げる Start Rstudio
- これも
- これも
- RコンソールでRcppパッケージをインストールして読み込み Install Rcpp package and load it in the R console panel of Rstudio.
install.packages("Rcpp") library(Rcpp)
#include <Rcpp.h> using namespace Rcpp; // [[Rcpp::export]] NumericMatrix gibbs(int N, int thin) { NumericMatrix mat(N, 2); double x = 0, y = 0; RNGScope scope; for(int i = 0; i < N; i++) { for(int j = 0; j < thin; j++) { x = R::rgamma(3.0, 1.0 / (y * y + 4)); y = R::rnorm(1.0 / (x + 1), 1.0 / sqrt(2 * x + 2)); } mat(i, 0) = x; mat(i, 1) = y; } return(mat); }
- RstudioのRコンソールに戻って Go back to R console in Rstudio then,
# c++ファイルを読み込んで sourceCpp("gibbs.cpp") # c++ファイルに作ってあるgibbs()という関数を使う gibbs(10,10)
- こうなる You are seeing this
練習 Practice 〜RstudioでC++を覚える
- こちらをいくつかやってみる Try some in this page.
- Vector_Subsetting
- "vectorsubsetting.cpp"という名前で保存 Save below as "vectorsubsetting.cpp"
#include <Rcpp.h> using namespace Rcpp; // [[Rcpp::export]] NumericVector positives(NumericVector x) { return x[x > 0]; } // [[Rcpp::export]] List first_three(List x) { IntegerVector idx = IntegerVector::create(0, 1, 2); return x[idx]; } // [[Rcpp::export]] List with_names(List x, CharacterVector y) { return x[y]; } // [[Rcpp::export]] NumericVector in_range(NumericVector x, double low, double high) { return x[x > low & x < high]; } // [[Rcpp::export]] NumericVector no_na(NumericVector x) { return x[ !is_na(x) ]; } bool is_character(SEXP x) { return TYPEOF(x) == STRSXP; } // [[Rcpp::export]] List charvecs(List x) { return x[ sapply(x, is_character) ]; }
- Rで読んで、実行する Read it into R and use it.
install.packages("microbenchmark") library(microbenchmark) sourceCpp("vectorsubsetting.cpp") R_in_range <- function(x, low, high) { return(x[x > low & x < high]) } x <- rnorm(1E5) identical( R_in_range(x, -1, 1), in_range(x, -1, 1) ) microbenchmark( times=5, R_in_range(x, -1, 1), in_range(x, -1, 1) )
-
- うまく動いたら、何をしているか確認してみる。It runs ok? then read codes to understand how it works.
- C++内でRの関数を使ってみる Use a R function in C++
- R function
x <- rnorm(1000) fivenum(x) # min,max,quantiles(x,c(0.25,0.5,0.75))
-
- "callfunction.cpp"
#include <Rcpp.h> using namespace Rcpp; // [[Rcpp::export]] NumericVector callFunction(NumericVector x, Function f) { NumericVector res = f(x); return res; }
-
- 使う Use it
sourceCpp("callfunction.cpp") callFunction(x,fivenum) fivenum(x)
> sourceCpp("callfunction.cpp") > callFunction(x,fivenum) [1] -2.96348996 -0.70554582 -0.01415115 0.66923375 3.05126692 > fivenum(x) [1] -2.96348996 -0.70554582 -0.01415115 0.66923375 3.05126692
Armadilloを使う 〜RstudioでC++を覚える
- Rcppパッケージの基本、それをRstudioで扱うことの基本はわかった
- けれど、「素のC++」だけでは、ごつすぎて使いにくい。特に線形代数とか、いわゆる数値計算のためのベクトル・行列・アレイなどが使いやすくて、それの演算ライブラリがないとだめなので、Armadilloを入れて、それを使えるようになることにする
- そもそもArmadilloはC++用の線形代数ライブラリ(こちら)
- それをRcppで使うようにしたのがRcppArmadilloパッケージなので、以下をして使えるようにする
install.packages("RcppArmadillo") library(RcppArmadillo)
- RcppArmadilloのチュートリアルとかもあるけれど、手っ取り早く、Rstudioで動かしているサンプルを見つけよう→こちら
- 結局、以下を"LinearRegression.cpp"という名前で保存して(これより上にヘッダーは不要(#include
も不要) - 逆行列計算ができていたり(solve)、行列の転置ができていたり(mX.t())、行列の積ができていたり(mX.t() * mX)するところがArmadilloライブラリの恩恵。List型でRに返したりしているところはRcppArmadilloパッケージの実装の恩恵
- 結局、以下を"LinearRegression.cpp"という名前で保存して(これより上にヘッダーは不要(#include
// LinearRegression.cpp // [[Rcpp::depends(RcppArmadillo)]] #include <RcppArmadillo.h> using namespace arma; // use the Armadillo library for matrix computations using namespace Rcpp; // [[Rcpp::export]] List fnLinRegRcpp(vec vY, mat mX) { // compute the OLS estimator & model residuals vec vBeta = solve(mX.t()*mX, mX.t()*vY); vec vResid = vY - mX * vBeta; // construct the return object List ret; ret["beta"] = vBeta; ret["resid"] = vResid; return ret; } // END
library(devtools) library(Rcpp) library(RcppArmadillo) Rcpp::sourceCpp("LinearRegression.cpp", showOutput = TRUE, rebuild = FALSE) # もちろんファイルの置き場所はこれでアクセスできるように…
-
- 関数を使う
# generate some sample data iK = 4 iN = 100 mX = cbind(1, matrix(rnorm(iK*iN), iN, iK)) vBeta0 = c(2, 3.5, 0.11, 6.33, 23) vY = rnorm(iN, mean = mX %*% vBeta0) # test the function linReg1 = fnLinRegRcpp(vY, mX) linReg1$beta # coefficient estimates # compare the results to the built-in lm.fit function lm.fit(y = vY, x = mX)$coef # coefficient estimates # END
C++を?
- 「C++かCを覚えてみる?」という話になった
- 一からやってもよいけれど、多分、飽きてしまうし、Rと連携して使うことが多そうだから、Rcppを使うことを前提にC++を覚えてみる、例題は自分たちがRで書いているコードをC++化する、ということにする、というようなやり方ではどうだろうか…
- こんな文書があった。これをなぞるかどうか考えてみる
- Rcpp Galleryも検討する
- Rstudioを使うならRcpp with Rstudio(En),RstudioでRcpp...(Jp)→RstudioでC++を覚える(考える暇があったらやってみよう)
- その他資料