我不知道是否有原生函数可用,但编写循环相对简单。
以下是三个版本。
其中两个版本找到向量的 Rcpp::max()
,然后找到与此最大值匹配的向量的索引。一个使用预先分配的Rcpp :: IntegerVector()
存储结果,然后对其进行子集,以删除多余的'未使用'零。另一个使用std :: vector< int >
并使用.push_back()
来存储结果。
library(Rcpp)
cppFunction('IntegerVector which_maxCpp1(NumericVector v) {
double m = Rcpp::max(v);
Rcpp::IntegerVector res( v.size() ); // pre-allocate result vector
int i;
int counter = 0;
for( i = 0; i < v.size(); ++i) {
if( v[i] == m ) {
res[ counter ] = i;
counter++;
}
}
counter--;
Rcpp::Range rng(0, counter);
return res[rng];
}')
v = c(1,2,3,1,2,3)
which_maxCpp(v)
# [1] 2 5
cppFunction('IntegerVector which_maxCpp2(NumericVector v) {
double m = Rcpp::max(v);
std::vector< int > res;
int i;
for( i = 0; i < v.size(); ++i) {
if( v[i] == m ) {
res.push_back( i );
}
}
Rcpp::IntegerVector iv( res.begin(), res.end() );
return iv;
}')
which_maxCpp(v)
# [1] 2 5
第三种选项通过在同一循环中找到最大值并跟踪索引来避免对向量进行双重传递。
cppFunction('IntegerVector which_maxCpp3(NumericVector v) {
double current_max = v[0];
int n = v.size();
std::vector< int > res;
res.push_back( 0 );
int i;
for( i = 1; i < n; ++i) {
double x = v[i];
if( x > current_max ) {
res.clear();
current_max = x;
res.push_back( i );
} else if ( x == current_max ) {
res.push_back( i );
}
}
Rcpp::IntegerVector iv( res.begin(), res.end() );
return iv;
}')
基准测试
以下是一些基准测试结果,展示了这些函数与基本的R方法相比的性能表现。
library(microbenchmark)
x <- sample(1:100, size = 1e6, replace = T)
microbenchmark(
iv = { which_maxCpp1(x) },
stl = { which_maxCpp2(x) },
max = { which_maxCpp3(x) },
r = { which( x == max(x)) }
)
which(v==max(v))
。 - MACHERKI M E