Rcpp max вектора, кроме одного элемента - PullRequest
0 голосов
/ 08 марта 2019

В Rcpp Я хочу найти максимум вектора, но я хочу опустить один элемент.

У меня есть рабочий код, но я уверен, что мой подход довольно плох, поскольку он включает в себя полную копию вектора. Есть ли намного лучший способ выполнить то, что я хочу?

В R:

vec <- 1:10
ele <- 3
max(vec[-ele])

Моя (ужасная) версия в Rcpp:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
double my_fun(NumericVector vec, int ele) {
    NumericVector vec_no_ele = clone(vec);
    vec_no_ele.erase(ele);
    return max(vec_no_ele);
}

Ответы [ 3 ]

1 голос
/ 09 марта 2019

Ответ @coatless великолепен и основан на других щедрых комментариях выше. Однако, это может быть далее обобщено. @coatless использует значение в vec[0] в качестве заполнителя для пропускаемого значения, но это не работает, когда пропускаемое значение является элементом 0!

Вот немного обобщенное решение, где я использую соседний элемент к ele в качестве заполнителя и проверяю, что ele находится в индексе vec и что vec.length() больше 1:

// calculate the max of a vector after omitting one element
double max_except(NumericVector vec, int ele) {
    if (vec.length() == 1) stop("vec too short");
    if (ele < 0 | ele > vec.length()-1) stop("ele out of range");
    double temp = vec[ele];
    int idx = (ele > 0) ? ele-1 : ele+1;
    vec[ele] = vec[idx];
    double res = max(vec);
    vec[ele] = temp;
    return res;
}
1 голос
/ 11 марта 2019

Под капотом max реализован как скромный цикл. Вы не должны уклоняться от циклов for в c ++, поскольку накладные расходы намного меньше, чем в R. В этом случае цикл for работает значительно лучше, чем использование встроенного:

// Coatless answer:
// [[Rcpp::export]]
double max_no_copy(NumericVector vec, int ele) {
  double temp = vec[ele-1];
  vec[ele-1] = vec[0];
  double result_max = max(vec);
  vec[ele-1] = temp;
  return result_max;
}

// humble for loop
// [[Rcpp::export]]
double max_except_for(NumericVector vec, int ele) {
  int vs = vec.size();
  double res = 0;
  for(int i=0; i<vs; i++) {
    if( i == ele-1 ) continue;
    if(vec[i] > res) res = vec[i];
  }
  return res;
}

R сторона:

x <- rnorm(1e8)
x[1000] <- 1e9
microbenchmark(max_except_for(x, 1000), max_no_copy(x, 1000), times=5)

Unit: milliseconds
                    expr       min        lq     mean    median       uq       max neval cld
 max_except_for(x, 1000)  87.58906  93.56962  92.5092  93.59754  93.6262  94.16361     5  a 
    max_no_copy(x, 1000) 284.46662 292.57627 296.3772 296.78390 300.5345 307.52455     5   b


identical(max_except_for(x, 1000), max_no_copy(x, 1000)) # TRUE
1 голос
/ 08 марта 2019

@ Spacemen предлагает следующий подход в комментариях:

Сохраните значение, которое вы хотите опустить, во временной переменной.Установите этот элемент в ноль или небольшое значение или то же самое, что и другое значение в векторе.Вычислить макс.Сбросьте элемент из временной переменной.

Это будет реализовано следующим образом:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
double max_no_copy(NumericVector vec, int ele) {
  double temp = vec[ele];

  // Use a value already in vector
  vec[ele] = vec[0];

  // Find max value
  double result_max = max(vec);

  // Remove NA value
  vec[ele] = temp;

  return result_max;
}

Тест:

vec <- 1:10
ele <- 2 # C++ indices start at 0 not 1. So, subtract.

max_no_copy(vec, ele)
# [1] 10

Тест будет добавлен позже...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...