在Rcpp中查找向量中所有最大/最小值的索引

3

假设我有一个向量

v = c(1,2,3)

我可以轻松地找到最大的元素,使用:
cppFunction('int which_maxCpp(NumericVector v) {
  int z = which_max(v);
  return z;
}')

which_maxCpp(v)

2

然而,如果我有一个向量,例如

v2 = c(1,2,3,1,2,3)

我也得到了

which_maxCpp(v2)

2

相比之下,我应该发现索引2和索引5(或使用1索引时的索引3和索引6)等于向量中的最大值

是否有一种方法可以获取which_max(或which_min),以找到向量的所有最小/最大元素的索引,或者需要另一个(我假设是本地C ++)函数?


你在使用R吗? - Shirin Yavari
是的,使用Rcpp包来封装C++代码。 - Robert Hickman
你需要两个步骤:第一步是找到最大值,第二步是获取索引。使用R语言,我可以建议使用which(v==max(v)) - MACHERKI M E
1个回答

5

我不知道是否有原生函数可用,但编写循环相对简单。

以下是三个版本。

其中两个版本找到向量的 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)) } 
)

# Unit: milliseconds
# expr      min        lq      mean    median       uq        max neval
#   iv 6.638583 10.617945 14.028378 10.956616 11.63981 165.719783   100
#  stl 6.830686  9.506639  9.787291  9.744488 10.17247  11.275061   100
#  max 3.161913  5.690886  5.926433  5.913899  6.19489   7.427020   100
#    r 4.044166  5.558075  5.819701  5.719940  6.00547   7.080742   100

这不是答案。我并不是在寻找向量中的最大值。我正在寻找与给定向量中最大值匹配的所有索引。在v2中,这应该是2和5(如果使用1索引,则为3和6,都可以)。 - Robert Hickman
1
这是一个很好的自定义函数示例,需要在此编写 - 由于效率原因,STL和Rcpp Sugar倾向于仅返回第一个匹配项。 - Dirk Eddelbuettel
我已更新使用R方法的基准测试。 - SymbolixAU
我已经更新了第三个选项,其性能与基本R非常接近。 - SymbolixAU

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接