BaşlayınÜcretsiz başlayın

Rcpp vektörlerinin boyutunu değiştirme

Rcpp vektör sınıfları, R vektörlerinin üzerine çok ince bir katman olarak tasarlanmıştır. Bu, performans açısından, bunları büyütmenin veya küçültmenin doğru boyutta yeni bir vektör oluşturup ilgili verileri kopyalamak anlamına geldiği sonucunu doğurur. Bu işlem çok yavaştır, bu yüzden kaçınmak gerekir.

Mümkünse, önce vektörün nihai boyutunu hesaplayıp ardından o boyutta ayıracak şekilde kodunu yapılandırmalısın.

R'de x[x > 0] ifadesine eşdeğer olarak, bir vektörden pozitif değerleri seçen bir örnek görelim. Kaç tane pozitif sayı olacağını önceden bilmediğin için, sıfır uzunlukta bir vektörle başlayıp her bulduğunda bir değer eklemek cazip gelebilir. Burada, push_back() bir değeri sona ekleyen bir işlevdir.

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

Ne yazık ki bu işlev yavaş olacaktır çünkü tekrar tekrar yeni vektörler oluşturup verileri kopyalaması gerekir. Daha iyisini yapabilir misin?

Bu egzersiz, kursun bir parçasıdır

Rcpp ile R Kodunu Optimize Etme

Kursa Göz Atın

Egzersiz talimatları

  • Daha verimli bir işlev olan good_select_positive_values_cpp() tanımını, pozitif sayıları seçecek şekilde tamamla.
    • İlk for döngüsünde, x'in i'inci öğesi sıfırdan büyükse n_positive_elements değişkenine bir ekle.
    • O döngüden sonra, boyutu n_positive_elements olan positive_x adlı bir sayısal vektör ayır.
    • İkinci for döngüsünde, yine x'in i'inci öğesinin sıfırdan büyük olup olmadığını kontrol et.
    • Büyükse, positive_x'in j'inci öğesini x'in i'inci öğesine eşitle, ardından j'yi bir artır.
  • Karşılaştırma için bad_select_positive_values_cpp() çalışma alanında mevcut. Zaman ölçümü farkını görmek için konsol çıktısını incele.

Uygulamalı etkileşimli egzersiz

Bu egzersizi bu örnek kodu tamamlayarak deneyin.

#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)
)
*/
Kodu Düzenle ve Çalıştır