ÎncepețiÎncepe gratuit

Nu modifica dimensiunea vectorilor Rcpp

Clasele de vectori Rcpp sunt concepute ca niște învelișuri foarte subțiri în jurul vectorilor R. Aceasta are o implicație importantă asupra performanței: mărirea sau micșorarea lor presupune crearea unui nou vector de dimensiunea potrivită și copierea datelor relevante. Aceasta este o operațiune foarte lentă, deci ar trebui evitată.

Dacă este posibil, structurează-ți codul astfel încât să calculezi mai întâi dimensiunea finală a vectorului, apoi să îl aloci cu acea dimensiune.

Să vedem un exemplu care selectează valorile pozitive dintr-un vector, echivalentul lui x[x > 0] în R. Deoarece nu știi dinainte câte numere pozitive vor fi, este tentant să începi cu un vector de lungime zero și să adaugi câte o valoare de fiecare dată când găsești una. Aici, push_back() este o funcție care adaugă o valoare la sfârșitul vectorului.

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;
}

Din păcate, această funcție va fi lentă, deoarece trebuie să creeze în mod repetat vectori noi și să copieze datele. Încearcă să găsești o soluție mai eficientă!

Acest exercițiu face parte din cursul

Optimizarea codului R cu Rcpp

Vezi cursul

Instrucțiuni pentru exercițiu

  • Completează definiția unei funcții mai eficiente, good_select_positive_values_cpp(), pentru a selecta numerele pozitive.
    • În primul ciclu for, dacă al i-lea element al lui x este mai mare decât zero, adaugă unu la n_positive_elements.
    • După acel ciclu for, alocă un vector numeric, positive_x, de dimensiunea n_positive_elements.
    • În al doilea ciclu for, verifică din nou dacă al i-lea element al lui x este mai mare decât zero.
    • Când este, setează al j-lea element al lui positive_x la valoarea celui de-al i-lea element al lui x, apoi adaugă unu la j.
  • bad_select_positive_values_cpp() este disponibilă în spațiul tău de lucru pentru comparație. Examinează rezultatele din consolă pentru a vedea diferența de timp de execuție măsurată prin benchmark.

Exercițiu interactiv practic

Încearcă acest exercițiu completând acest cod de exemplu.

#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)
)
*/
Editează și rulează codul