c++
を使用して短い記述for
ループはどうですかRcpp
。この小さな関数はnumeric
ベクトル、つまりordernum
列とthreshold
引数 (新しい ID を開始する累積合計) を取り、入力ベクトルと等しい長さの ID のベクトルを返します。for
のループであるため、比較的速く実行する必要がありますc++
。以下のコード スニペットRcpp
は、まだインストールされていない場合にインストールされ、使用できるように関数をコンパイルします。コピーしてRに貼り付けるだけです...
if( !require(Rcpp) ) install.packages("Rcpp"); require(Rcpp)
Rcpp::cppFunction( ' NumericVector grpid( NumericVector x , int threshold ){
int n = x.size();
NumericVector out(n);
int tot = 0;
int id = 1;
for( int i = 0; i < n; ++i){
tot += x[i];
out[i] = id;
if( tot >= threshold ){
id += 1;
tot = 0;
}
}
return out;
}')
次に、関数を使用するには、関連する引数を指定して、他の R 関数と同様に使用します。
df$groupid <- grpid( df$ordernum , 30 )
# productid ordernum groupid
#1 p1 10 1
#2 p2 20 1
#3 p3 30 2
#4 p4 5 3
#5 p5 20 3
#6 p6 8 3
ベンチマーク比較
OPは、ベースR forループに対してRcppループをベンチマークするように私に依頼しました。これがコードと結果です。100,000 個の製品 ID のベクトルで約 400 倍の速度向上:
set.seed(1)
x <- sample(30,1e5,repl=T)
for.loop <- quote({
tot <- 0
id <- 1
out <- numeric(length(x))
for( i in 1:length(x) ){
tot <- tot + x[i]
out[i] <- id
if( tot >= 30 ){
tot <- 0
id <- id + 1
}
}
})
rcpp.loop <- quote( out <- grpid(x,30))
require( microbenchmark )
print( bm , unit = "relative" , digits = 2 , "median" )
Unit: relative
expr min lq median uq max neval
eval(rcpp.loop) 1 1 1 1 1 50
eval(for.loop) 533 462 442 428 325 50