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
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 luixeste mai mare decât zero, adaugă unu lan_positive_elements. - După acel ciclu
for, alocă un vector numeric,positive_x, de dimensiunean_positive_elements. - În al doilea ciclu
for, verifică din nou dacă al i-lea element al luixeste mai mare decât zero. - Când este, setează al j-lea element al lui
positive_xla valoarea celui de-al i-lea element al luix, apoi adaugă unu laj.
- În primul ciclu
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)
)
*/