MulaiMulai sekarang secara gratis

Jangan ubah ukuran vektor Rcpp

Kelas vektor Rcpp dirancang sebagai pembungkus yang sangat tipis di atas vektor R. Implikasi kinerjanya adalah menambah atau mengurangi ukurannya berarti membuat vektor baru dengan ukuran yang benar lalu menyalin data yang relevan. Ini sangat lambat, sehingga sebaiknya dihindari.

Jika memungkinkan, Anda sebaiknya menyusun kode untuk terlebih dahulu menghitung ukuran akhir vektor, lalu mengalokasikannya dengan ukuran tersebut.

Mari lihat contoh yang memilih nilai positif dari sebuah vektor, setara dengan x[x > 0] di R. Karena Anda tidak tahu sebelumnya berapa banyak bilangan positif yang akan ada, godaan yang muncul adalah memulai dengan vektor berdimensi nol dan menambahkan nilai setiap kali menemukannya. Di sini, push_back() adalah fungsi yang menambahkan sebuah nilai di akhir vektor.

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

Sayangnya, fungsi ini akan lambat karena harus berulang kali membuat vektor baru dan menyalin data. Coba lihat apakah Anda bisa membuatnya lebih baik!

Latihan ini adalah bagian dari kursus

Mengoptimalkan Kode R dengan Rcpp

Lihat Kursus

Petunjuk latihan

  • Lengkapi definisi fungsi yang lebih efisien, good_select_positive_values_cpp() untuk memilih bilangan positif.
    • Pada for loop pertama, jika elemen ke-i dari x lebih besar dari nol, tambahkan satu ke n_positive_elements.
    • Setelah loop tersebut, alokasikan sebuah vektor numerik, positive_x, berukuran n_positive_elements.
    • Pada for loop kedua, kembali periksa apakah elemen ke-i dari x lebih besar dari nol.
    • Jika ya, atur elemen ke-j dari positive_x menjadi elemen ke-i dari x lalu tambahkan satu ke j.
  • bad_select_positive_values_cpp() tersedia di ruang kerja Anda untuk perbandingan. Periksa keluaran konsol untuk melihat perbedaan waktu eksekusi hasil benchmark.

Latihan interaktif praktis

Cobalah latihan ini dengan menyelesaikan kode contoh berikut.

#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)
)
*/
Edit dan Jalankan Kode