このページはまだ作成中なのであしからず。
要約は下のRcppのすすめ スライドを見てください。 DocumentはC++がわかる人向け 基本データ型
正確には、Rcppで基本データ型として定義されているのは String, Date, Datetime のみで、その他の型ついてはC++の基本型を利用する。 データ構造Rcppの基本データ型のそれぞれについて ◯◯Vector、◯◯Matrix NumericVector、NumericMatrixなど 文字列については、StringVector、CharacterVector のどちらでも良い。 ベクターを要素として格納できる Dataframe、List ベクターの作成と要素へのアクセス作成 NumericVector v(10);//0が10個並んだベクター NumericVector v = NumericVector::create(1,1,1);//1が3個並んだベクター NumericVector v = NumericVector::create(Named("名前1") = 1 , _["名前2"]=2); //要素に名前をつける場合 NumericVector v = {1,1,1}; //1が3個、イニシャライザリストを使った例(C++11) 要素へのアクセス v[0] //要素番号でアクセス(最初の要素番号は0) v["名前"] //要素の名前でアクセス v[L]//論理値ベクターでアクセス double sum=0; for(int i=0; i<v.length(); ++i){ sum += v[i]; } Matrix の作成と要素へのアクセス作成 NumericMatrix m(2, 3); 2行3列、値は0の行列 要素へのアクセス m( 0 , 2 ); 0行2列の要素にアクセス m( 0 , _ ); 0行目全体 m( _ , 2 ); 2列目全体 m( Range(0,1) , Range(2,3) ); //(0〜1)行、(2〜3)列のmの部分行列 NumericVector v = m( 0, _ ); //0行目の値をベクター v にコピーする NumericMatrix::Column col = m( _ , 1); //mの1列目の値を参照したいだけの時(データのコピーが発生しない) NumericMatrix::Row row = m( 1 , _ ); //mの1行目の値を参照 NumericMatrix::Sub sub = m( Range(0,1) , Range(2,3) );//mの部分行列を参照 col = col*2; //とすると m の 1 列目の値を2倍にすることができる sub = sub*2; //こちらも m の (0〜1)行、(2〜3)列 の要素を2倍にする v = v*2; //こちらは m には影響しない データフレームの作成と要素へのアクセスDataFrame df = DataFrame::create(v1, v2); //ベクター v1, v2 からデータフレーム df を作成 DataFrame df = DataFrame::create(Named("名前1") = v1 , _["名前2"]=v2); //列に名前をつける場合 要素へのアクセス NumericVector v = df[0]; //dfの0列目をベクター v に代入 //この場合、v には df[0] の値がコピーされるのではなく、df[0]への参照となる v = v*2; //こうすると df[0] の値が2倍になる NumericVector v = clone(df[0]); //値をコピーしたい場合は clone() を使う リストの作成と要素へのアクセスデータフレームと基本的に同じ List L = List::create(v1, v2); //ベクター v1, v2 からリスト L を作成 List L = List::create(Named("名前1") = v1 , _["名前2"]=v2); //要素に名前をつける場合 要素へのアクセス NumericVector v = L[0]; //dfの0列目をベクター v に代入 //この場合、v には L[0] の値がコピーされるのではなく、L[0]への参照となる v = v*2; //こうすると L[0] の値が2倍になる NumericVector v = clone(L[0]); //値をコピーしたい場合は clone() を使う Rcppオブジェクトで代入する際の注意点NumericVector myFunc(NumericVector A){ A[0]=100; NumericVector B=A; B[1]=200; return(A); }//A==c(100,200,3,4,5) B への変更が A に影響する これはB=Aとした時に、BにはAの値をコピーされるのではなく、BはAへの「参照」として代入されるため(AとBは同じオブジェクトを指している)。Bへのアクセスすると結局Aへアクセスすることになるため。 下のように、clone を使うと B へ A の値がコピーされる。AとBは別のオブジェクトとなる。 NumericVector myFunc(NumericVector A){ A[0]=100; NumericVector B=clone(A); B[1]=200; return(A); }//A==c(100,200,3,4,5) B への変更が A に影響する Rcpp のオブジェクト間で = を使うときには、「参照」として代入されているのか、「値をコピー」して代入されているのか注意する必要がある。 ベクトルの長さなど属性値◯◯Vector V; V.names() //要素名 V.length() //長さ ◯◯Matrix M; M.ncol() //列数 M.nrow() //行数 M.attr(“dimnames”)=List::create(行名ベクタ, 列名ベクタ); //行名、列名へはリストでアクセスする DataFrame DF; DF.nrows() //行数 DF.size() //列数 DF.attr(“names”)//列名 DF.attr(“row.names”)//行名 List L; L.attr(“names”)//要素名 ベクトル演算 四則演算は R と同様の記法でOK
NumericVector x ;
NumericVector y ; // expressions involving two vectors
NumericVector res = x + y ;
NumericVector res = x - y ;
NumericVector res = x * y ;
NumericVector res = x / y ;
// one vector, one single value
NumericVector res = x + 2.0 ;
NumericVector res = 2.0 - x;
NumericVector res = y * 2.0 ;
NumericVector res = 2.0 / y;
// two expressions
NumericVector res = x * y + y / 2.0 ;
NumericVector res = x * ( y - 2.0 ) ;
NumericVector res = x / ( y * y ) ;
-演算子で符号を反転
// negate x
NumericVector res = -x ;
論理ベクター数値ベクトル同士の値の比較により、論理ベクトルを生成するのも、Rと同様
// two integer vectors of the same size
NumericVector x ;
NumericVector y ;
// expressions involving two vectors
LogicalVector res = x < y ;
LogicalVector res = x > y ;
LogicalVector res = x <= y ;
LogicalVector res = x >= y ;
LogicalVector res = x == y ;
LogicalVector res = x != y ;
// one vector, one single value
LogicalVector res = x < 2 ;
LogicalVector res = 2 > x;
LogicalVector res = y <= 2 ;
LogicalVector res = 2 != y;
// two expressions
LogicalVector res = ( x + y ) < ( x*x ) ;
LogicalVector res = ( x + y ) >= ( x*x ) ;
LogicalVector res = ( x + y ) == ( x*x ) ;
// ! 演算子で論理値を反転
// negate the logical expression "y < z"
LogicalVector res = ! ( x < y );
論理値ベクターを使って、ベクターの要素にアクセスできる。
x[x < 2]
Rcpp が提供する R ライクな関数ベクター関係
head, tail, rep_each(), rep_len(), rep(), rev()
seq_along(), seq_len(), cumsum(), diff(), pmin(), and pmax()
数学関数
要約統計量
値の検索
match() , self_match() , which_max() , which_min() 重複の値
duplicated() , unique()
確率分布
ベクターがNAを含まないことを保証できるなら、以下のようにすると計算が早くなる
noNA(x) seq_lenNumericVector x(10);
x = seq_len(10); //1:10
seq_alongIntegerVector x = IntegerVector::create( 0, 1, NA_INTEGER, 3 ) ;
seq_along( x ) // 1:length(x)
rep_lenNumericVector x1 = rep_len(x, n);
all, anybool res = is_true( any( x < y ) )
bool res = is_false( any( x < y ) )
bool res = is_na( any( x < y ) )
NA// [[Rcpp::export]]
IntegerVector timesTwo() {
IntegerVector y = {1,NA_INTEGER,3}; //C++11 イニシャライザリスト
//IntegerVector::create( 1, NA_INTEGER, 3 ) ; //通常版
//y[1] C++ では変な値が入っているので注意
return 2*y;
}
> timesTwo()
[1] 2 NA 6
pmin, pmaxNumericVector z = pmin(x, y) //x[i] と y[i] を比較して小さい方を z[i] とする
NumericVector z = pmax(x, y) //x[i] と y[i] を比較して大きい方を z[i] とする
ifelse(x > y, z, w); //(x>y)[i] が真なら、z[i], 偽なら w[i]
ifelse(x > y, 1, w); //(x>y)[i] が真なら、1, 偽なら w[i]
sapply第1引数の各要素に、第2引数で与えた関数を適用した、結果をベクターで返す
//テンプレート関数を渡す場合
template <typename T>
T square( const T& x){
return x * x ;
}
sapply( seq_len(10), square<int> ) ;
//関数オブジェクトを与える場合
template <typename T>
struct square : std::unary_function<T,T> {
T operator()(const T& x){
return x * x ;
}
}
sapply( seq_len(10), square<int>() ) ;
//std::function と ラムダ式で書く場合
std::function<int (int)> func_obj = [](int x) { return (x*x);};
sapply( seq_len(10), func_obj) ;
sapplyと似ているが、返り値がlistになっている。
sign数値ベクターを受け取り、その各要素の符号に応じて、-1,0,1の値を格納したベクターを返す。
> sign(-3:3)
[1] -1 -1 -1 0 1 1 1
diff与えた数値ベクターの隣り合う要素の差を格納したベクターを返す。
y = diff(x) // y[i] == x[i+1] - x[i]
> diff(c(1,4,6))
[1] 3 2
数学関数abs(x) //絶対値
exp(x) //eのx乗
floor(x) //xの切り下げ
ceil(x) //xの切り上げ
pow(x, 2) //xの2乗
分布関数詳しくは、リファレンスを参照
d〜, p〜, q〜 の第1引数はベクトル化されている
p = dnorm(x, 0, 1); // 値 x における確率密度の値 p at 平均=0, 標準偏差=1
p = pnorm(x, 0, 1); // 値 x における累積分布の確率点 p
x = qnorm(p, 0, 1); // 累積分布の確率点が p となる値 x (pnorm の逆関数)
x = rnorm(n, 0, 1); // ’n’ RNG draws of N(0, 1) // n個の乱数
//各関数の引数はRの関数のものと対応している
//Rcpp のリファレンスと R のヘルプを良く見比べること
double dnorm (double x, double mu, double sigma, int lg)
//lg =1 は確率を対数で返す
pnorm (double x, double mu, double sigma, int lt, int lg)
//lt = 1 は左から確率を累積、lt = 0 は右から確率を累積
乱数乱数関数を使う前には RNGscope scope; のオブジェクトを作る。これはRcppが Rcpp の 関数を呼び出した Rの環境の乱数系列を受け取り、Rcpp で乱数を実行して系列を進めた後、続きの乱数系列を元のRの環境に戻すために使うらしい。RNGscope の呼び出しにはオーバーヘッドがかかるので、乱数関数の内部でそれを実装するのではなく、ユーザーが適切な位置でそれを記述することにしている。しかし、sourceCpp() がやってくれるので実は書く必要がないみたい。
In addition, we have the RNGScope class, whose constructor calls GetRNGstate and destructor calls PutRNGstate. RNGscope scope;// also done by sourceCpp()
rnorm(n, 0, 1);
C++ から R オブジェクトの属性にアクセスする.attr()
.names()
S4 オブジェクトに対しては .slot() が .attr() と似たような働きをする。
List と DataFrameこれらは引数として使う事が多い。
R の lm() の返り値はリストでその要素はS3オブジェクト
ここでは R の lm() の返り値を受け取る C++ 関数の例を示す。
List クラスの メンバ関数 .inherits() と stop で lm のオブジェクトかどうかチェックしている。
mod["要素名"] で リストの各要素にアクセス
as<型名>() で Rcpp クラスに変換
List を返す関数の例
template <typename T>
T square( const T& x){
return x * x ;
}
// [[Rcpp::export]]
List foo2( NumericVector x ){
return lapply( x, square<double> ) ;
}
length, values はベクター
FunctionR の関数を引数として渡して、Rcpp内で呼び出せる
lapply を Rcpp で実装
関数がどんな型を返すかわからない時は、どんな型でも代入できる、RObject のオブジェクトか、List の要素に代入する。
どちらもできる。
Function クラスのオブジェクトから、R の関数を呼び出し方。
引数を位置で指定するとき
引数の名前で指定するときは次のように書く
欠損値NA_INTEGER,
NA_REAL
NA_STRING
NA_LOGICAL
NA_LOGICAL を bool 型に代入した時だけ、挙動が異なる。
Integer
NA_INTEGER は int型 に代入えすると、int 型の最小値の値を取る。Rcpp ではこのオブジェクトを R に返すとき NA に変換する。
C++ 中では数値として扱われるので注意が必要。
Double
C++ には NAN があるので 非数値は扱える、R の NaN に変換される。
C++
NAN == 1; //false、全ての論理比較は false
NAN == NAN; //false
//下には注意が必要
NAN && TRUE; //true
NAN || FALSE; //true
//NAN に数値演算すると NAN になる
NAN +1; //NAN
String クラスは文字列スカラーを扱うために Rcpp が用意したクラスなので NA の扱いは心得ている。
R の論理型は TRUE, FALSE, NA の値を取る、NA をC++の bool 型に変換すると true になってしまうので注意が必要。
ベクターに値としてNA を入れたい場合は、ベクターの型に合わせてNA_INTEGER,
NA_REAL
NA_STRING
NA_LOGICAL
を使う。
ベクタの要素がNA かどうか調べたいときは、ベクターのメソッド ::is_na() を使う。
あるいは suger の is_na() を使うと、論理ベクターを返す
イテレーターRcpp のデータ構造はイテレータを持つ
C++ STLSTL にはイテレータを扱う様々なアルゴリズムが用意されている。
STLアルゴリズムを使って、R の findInterval と同等の関数を作成した。
x に数値ベクター、 breaks も数値ベクターでヒストグラムなどで値の範囲を表す区切り。
x の各要素が、どの範囲(いわゆるビン)に属するか表す整数ベクターを返す。
C++のソースにRのコードを埋め込むC++ コード内に、/*** R で始まるコメント内に Rのコードを書くと、sourceCpp()した時に、それが実行される。・
/*** R
# Call the fibonacci function defined in C++
fibonacci(10)
*/
関数名を変えるRで使う時の関数名を変えることができる。
// [[Rcpp::export(".convolveCpp")]]
NumericVector convolveCpp(NumericVector a, NumericVector b)
Rにエキスポートする関数の制約
乱数生成器C や C++ から R の乱数生成器を利用する際には注意がいる。GetRNGstate と PutRNGstate を適切に呼び出さないといけない。
Rcpp ではそれを RNGScope クラスにより解決している。しかし、// [[Rcpp::export]] でエキスポートされ、sourceCpp で読み込まれた関数の場合は、それが自動的に行われるので、ソースコードに記述する必要はない。RNGScope はカウンターを使って実装されているので、仮に RNGScope を記述しても問題はない。
依存パッケージ依存するパッケージを記述できる
// [[Rcpp::depends(RcppArmadillo)]]
複数のパッケージに依存する場合は、上のような記述を繰り返すか、下のように書く
// [[Rcpp::depends(Matrix, RcppArmadillo)]]
sourceCpp() は指定された依存パッケージに自動的にリンクする。
インラインで C++ を記述R コード中で C++ を記述する方法はいくつかある。一つは文字列オブジェクトしてsourceCpp()に渡す。もう一つは、cppFunction と evalCpp を使う。
cppFunction('
int fibonacci(const int x) {
if (x < 2)
return x;
else
return (fibonacci(x - 1)) + fibonacci(x - 2);
}
')
evalCpp('std::numeric_limits<double>::max()')
依存パッケージも cppFunction か evalCpp で指定できる。
cppFunction(depends = 'RcppArmadillo', code = '...')
|