開始使用免費開始

不要改變 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)
)
*/
編輯並執行程式碼