IniziaInizia gratis

Medie mobili (in C++)

La funzione vettorializzata per la media mobile, rollmean3(), aveva buone prestazioni ma una leggibilità molto scarsa. È davvero difficile capire che questo codice calcola una media mobile, il che rende la funzione più difficile da fare debug e da mantenere.

La seconda versione, rollmean2(), era più lenta ma più facile da leggere. Se la traduciamo in C++, auspicabilmente otterremo sia una buona leggibilità sia prestazioni elevate.

rollmean2() è definita nel tuo workspace; puoi stamparne la definizione per ricordarti come funziona. Ora tradurrai rollmean2() in C++, assegnandola a rollmean4().

Questo esercizio fa parte del corso

Ottimizzare il codice R con Rcpp

Visualizza il corso

Istruzioni dell'esercizio

  • Imposta res come NumericVector di lunghezza n e con valori restituiti dal metodo get_na() di NumericVector.
  • Calcola total come la somma dei primi window valori di x.
  • Calcola la media in window - 1 come il totale diviso per l'ampiezza della finestra.
  • Nel secondo ciclo, aggiorna il totale sottraendo l'elemento i - window-esimo di x e aggiungendo l'elemento i-esimo di x.

Esercizio pratico interattivo

Prova a risolvere questo esercizio completando il codice di esempio.

#include 
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector rollmean4(NumericVector x, int window) {
  int n = x.size();
  
  // Set res as a NumericVector of NAs with length n
  NumericVector res(___, ___::___());
  
  // Sum the first window worth of values of x
  double total = 0.0;
  for(int i = 0; i < window; i++) {
    total += ___;
  }
  
  // Treat the first case seperately
  res[window - 1] = ___ / window;
  
  // Iteratively update the total and recalculate the mean 
  for(int i = window; i < n; i++) {
    // Remove the (i - window)th case, and add the ith case
    total += - ___ + ___;
    // Calculate the mean at the ith position
    res[i] = total / window;
  }
  
  return res;  
}

/*** R
   # Compare rollmean2, rollmean3 and rollmean4   
   set.seed(42)
   x <- rnorm(1e4)
   microbenchmark( 
    rollmean2(x, 4), 
    rollmean3(x, 4), 
    rollmean4(x, 4), 
    times = 5
   )   
*/
Modifica ed esegui il codice