不要改變 Rcpp 向量的大小
Rcpp 向量類別是 R 向量的極薄包裝。這表示在效能上,一旦要擴增或縮小它們,就必須建立一個新向量並複製相關資料。這非常耗時,因此應盡量避免。
如果可以,請先在程式碼中計算出向量的最終大小,然後再以該大小配置。
以下示範如何從向量中選出正值,等同於 R 中的 x[x > 0]。由於你事先不知道會有多少個正數,很容易想從長度為 0 的向量開始,並在每次找到正值時附加一個元素。這裡的 push_back() 是用來附加值的函式。
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;
}
不幸的是,這個函式會很慢,因為它必須不斷建立新向量並複製資料。看看你能否做得更好!
本練習屬於課程
用 Rcpp 最佳化 R 程式碼
練習說明
- 完成更有效率的函式
good_select_positive_values_cpp(),用來選出正數。- 在第一個
for迴圈中,如果x的第 i 個元素大於 0,則讓n_positive_elements加 1。 - 該迴圈之後,配置一個大小為
n_positive_elements的數值向量positive_x。 - 在第二個
for迴圈中,再次檢查x的第 i 個元素是否大於 0。 - 若是,將
positive_x的第 j 個元素設為x的第 i 個元素,然後讓j加 1。
- 在第一個
- 你的工作空間中已提供
bad_select_positive_values_cpp()供比較。請查看主控台輸出,以了解執行時間的效能差異。
動手互動練習
試著完成這個範例程式碼,體驗一下這個練習。
#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)
)
*/