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
Petunjuk latihan
- Lengkapi definisi fungsi yang lebih efisien,
good_select_positive_values_cpp()untuk memilih bilangan positif.- Pada
forloop pertama, jika elemen ke-i darixlebih besar dari nol, tambahkan satu ken_positive_elements. - Setelah loop tersebut, alokasikan sebuah vektor numerik,
positive_x, berukurann_positive_elements. - Pada
forloop kedua, kembali periksa apakah elemen ke-i darixlebih besar dari nol. - Jika ya, atur elemen ke-j dari
positive_xmenjadi elemen ke-i darixlalu tambahkan satu kej.
- Pada
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)
)
*/