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을 더하세요. - 그
for루프 이후, 크기가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)
)
*/