2 min read

Rcpp-2

本文延續Rcpp-1

從R傳遞資料到C++

傳遞到對應的物件

Vector

在R的底層之中,最基礎的資料型態就是某六種型態的vector(詳情請見下表)。 傳遞這六種資料型態的vector到C++並不難,只要宣告對應的Rcpp class以及把透過.Call傳遞進來的SEXP丟到Rcpp class的constructor內就好了。

表一:

atomic type Rcpp Class
logical LogicalVector
integer IntegerVector
double NumericVector
complex ComplexVector
character CharacterVector
raw RawVector

ps. 在R中,幾乎所有物件都是vector

integer為例子:

``` cpp test-rcpp.cpp #include <Rcpp.h>

using namespace Rcpp;

RcppExport SEXP R2CppInteger(SEXP RIntegerVec);

SEXP R2CppInteger(SEXP r_int_vec) { IntegerVector int_vec(r_int_vec); for (R_len_t i(0);i < int_vec.length();i++) { Rprintf(“%d”, int_vec[i]); } Rprintf(“length: %d ”, int_vec.length()); return R_NilValue; }


編譯後,在R底下執行

``` r test.R
dyn.load("test-rcpp.so")
a <- 1L:10L
.Call("R2CppInteger", a)
dyn.unload("test-rcpp.so")

就會看到輸出

1 2 3 4 5 6 7 8 9 10 
 length: 10 
NULL

如果需要使用上的細節,只需要查閱Rcpp Reference中關於Vector的部分。

而Rcpp還有許多可以直接傳遞其他進階的R物件的C++物件。

Matrix

因為R中的matrix 或 array 物件其實就是加上dimension的vector,所以可以直接用xxxVector物件在C++內處理。 Rcpp中另外還有更類似R的matrix的xxxMatrix物件。 只是要注意,在C++裡面取出來的row或column在C++裡的型態會是Rcpp::xxxMatrix::RowRcpp::xxxMatrix::Column。請見以下範例:

``` cpp test-rcpp.cpp #include <Rcpp.h>

using namespace Rcpp;

RcppExport SEXP R2CppInteger(SEXP RIntegerVec);

SEXP R2CppInteger(SEXP r_int_mat) { IntegerMatrix int_mat(r_int_mat); Rprintf(“print the matrix”); for(int i(0);i < int_mat.nrow();i++) { for(int j(0);j < int_mat.ncol();j++) { Rprintf(“%d”, int_mat(i, j)); } Rprintf(“”); } Rprintf(“print the first column:”); IntegerMatrix::Column int_mat_col( int_mat(internal::NamedPlaceHolder(), 0 ) ); for(int i(0);i < int_mat.nrow();i++) { Rprintf(“%d”, int_mat_col[i]); } Rprintf(“”); return R_NilValue;
}


編譯之後在R底下執行
``` r
dyn.load("test-rcpp.so")
a <- matrix(1L:10L, 2, 5)
.Call("R2CppInteger", a)
dyn.unload("test-rcpp.so")

就可以看到輸出

print the matrix
1 3 5 7 9 
2 4 6 8 10 
print the first column: 1 2 
NULL

List

list物件在R也是非常的重要,而且和上述的vector型態已經不一樣了。 在R中,一個vector內的資料一定只能是相同的atomic type,但是在list中就可以放不同的atomic type。 說穿了,List物件也只是R物件的vector,這從Rcpp中List的定義:typedef Vector<VECSXP> List可窺見一二。

``` cpp test-rcpp.cpp #include <Rcpp.h>

using namespace Rcpp;

RcppExport SEXP R2CppList(SEXP RList);

Function show(“show”);

SEXP R2CppList(SEXP RList) { List list(RList); for (R_len_t i = 0;i < list.size();i++) { show(list[i]); } return R_NilValue; }


ps. 這裡的Function是Rcpp中呼叫R function的方式,之後會再介紹。這裡的用途只是把傳入的東西以R中的`show`函數顯示到console上。

編譯之後在R底下執行
``` r
dyn.load("test-rcpp.so")
a <- list()
a[[1]] <- 1L:10L
a[['a']] <- paste("test", 1:10)
a[[2]] <- factor(sample(1:2, 10, TRUE))
.Call("R2CppList", a)

就可以看到:

 [1]  1  2  3  4  5  6  7  8  9 10
 [1] 2 2 1 2 2 1 2 1 1 2
Levels: 1 2
NULL

data.frame

data.frame 其實就只是滿足某些條件的List物件,所以是可以用List物件來做處理的。 除此之外Rcpp也提供C++物件:DataFrame給使用者。 但是目前除了提供方便的建立DataFrame物件之外,只有類似List的操作方法。在此就不提供範例了。

傳遞到STL物件

Rcpp可以利用as<>函數將R物件轉換成對應的STL物件 。