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
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 dexfor maior que zero, some um an_positive_elements. - Depois desse laço
for, aloque um vetor numérico,positive_x, de tamanhon_positive_elements. - No segundo laço
for, verifique novamente se o elemento i dexé maior que zero. - Quando for, defina o elemento j de
positive_xcomo o elemento i dexe então some um aj.
- No primeiro laço
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)
)
*/