Comece agoraComece grátis

Não altere o tamanho de vetores Rcpp

As classes de vetores do Rcpp são projetadas como invólucros muito finos sobre vetores do R. Isso implica, em termos de desempenho, que aumentá-los ou diminuí-los significa criar um novo vetor do tamanho correto e copiar os dados relevantes. Essa é uma tarefa muito lenta e deve ser evitada.

Sempre que possível, você deve estruturar seu código para primeiro calcular o tamanho final do vetor e só então alocá-lo com esse tamanho.

Vamos ver um exemplo que seleciona os valores positivos de um vetor, equivalente a x[x > 0] em R. Como você não sabe de antemão quantos números positivos existirão, é tentador começar com um vetor de tamanho zero e acrescentar um valor toda vez que encontrar um. Aqui, push_back() é uma função que acrescenta um valor.

NumericVector bad_select_positive_values_cpp(NumericVector x) {
  NumericVector positive_x(0);
  for(int i = 0; i < x.size(); i++) {
    if(x[i] > 0) {
      positive_x.push_back(x[i]);
    }
  }
  return positive_x;
}

Infelizmente, essa função será lenta porque precisa criar novos vetores repetidamente e copiar os dados. Veja se você consegue fazer melhor!

Este exercicio faz parte do curso

Otimizando código R com Rcpp

Ver curso

Instruções do exercicio

  • Complete a definição de uma função mais eficiente, good_select_positive_values_cpp(), para selecionar os números positivos.
    • No primeiro laço for, se o elemento i de x for maior que zero, some um a n_positive_elements.
    • Depois desse laço for, aloque um vetor numérico, positive_x, de tamanho n_positive_elements.
    • No segundo laço for, verifique novamente se o elemento i de x é maior que zero.
    • Quando for, defina o elemento j de positive_x como o elemento i de x e então some um a j.
  • bad_select_positive_values_cpp() está disponível no seu workspace para comparação. Examine a saída do console para ver a diferença de tempo de execução medida por benchmark.

exercicio interativo prático

Tente este exercicio completando este código de exemplo.

#include 
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector good_select_positive_values_cpp(NumericVector x) {
  int n_elements = x.size();
  int n_positive_elements = 0;
  
  // Calculate the size of the output
  for(int i = 0; i < n_elements; i++) {
    // If the ith element of x is positive
    if(___) {
      // Add 1 to n_positive_elements
      ___;
    }
  }
  
  // Allocate a vector of size n_positive_elements
  ___;
  
  // Fill the vector
  int j = 0;
  for(int i = 0; i < n_elements; i++) {
    // If the ith element of x is positive
    if(___) {
      // Set the jth element of positive_x to the ith element of x
      ___;
      // Add 1 to j
      ___;
    }
  }
  return positive_x;
}

/*** R
set.seed(42)
x <- rnorm(1e4)
# Does it give the same answer as R?
all.equal(good_select_positive_values_cpp(x), x[x > 0])
# Which is faster?
microbenchmark(
  bad_cpp = bad_select_positive_values_cpp(x),
  good_cpp = good_select_positive_values_cpp(x)
)
*/
Editar e Executar Código