수색…


Rcpp를 사용하여 반복적으로 벡터화하는 속도가 빨라짐

첫 번째 요소가 지정되고 ( first ) 각 요소 x_icos(x_{i-1} + 1) 과 같은 길이 len 의 벡터를 만드는 다음 터프 투 벡터 화 루프를 고려하십시오.

repeatedCosPlusOne <- function(first, len) {
  x <- numeric(len)
  x[1] <- first
  for (i in 2:len) {
    x[i] <- cos(x[i-1] + 1)
  }
  return(x)
}

이 코드에는 빠른 연산 ( cos(x[i-1]+1) )을 사용하는 for 루프가 포함되며, 종종 벡터화의 이점을 얻습니다. 그러나 R에 "x + 1의 누적 코사인"함수가 없으므로이 연산을 기준 R로 벡터화하는 것은 쉽지 않습니다.

이 함수의 속도를 높이는 한 가지 가능한 접근법은 Rcpp 패키지를 사용하여 C ++로 구현하는 것입니다.

library(Rcpp)
cppFunction("NumericVector repeatedCosPlusOneRcpp(double first, int len) {
  NumericVector x(len);
  x[0] = first;
  for (int i=1; i < len; ++i) {
    x[i] = cos(x[i-1]+1);
  }
  return x;
}")

이는 대개 큰 계산에 대해 상당한 속도 향상을 제공하는 동시에 정확한 결과를 산출합니다.

all.equal(repeatedCosPlusOne(1, 1e6), repeatedCosPlusOneRcpp(1, 1e6))
# [1] TRUE
system.time(repeatedCosPlusOne(1, 1e6))
#    user  system elapsed 
#   1.274   0.015   1.310 
system.time(repeatedCosPlusOneRcpp(1, 1e6))
#    user  system elapsed 
#   0.028   0.001   0.030 

이 경우, Rcpp 코드는 기본 R 방식으로 1.31 초 대신 0.03 초에 길이 1 백만의 벡터를 생성합니다.

바이트 컴파일을 통한 루프에 대한 터프 투 벡터 라이팅 속도 향상

이 문서 입력에 Rcpp 예를 따르면, 길이의 벡터 생성 다음 거친 투 벡터화 기능 고려 len 제 소자 (지정된 first ) 각 소자 x_i 같은지 cos(x_{i-1} + 1) :

repeatedCosPlusOne <- function(first, len) {
  x <- numeric(len)
  x[1] <- first
  for (i in 2:len) {
    x[i] <- cos(x[i-1] + 1)
  }
  return(x)
}

한 줄의 코드를 다시 작성하지 않고 이러한 기능을 빠르게하는 간단한 방법은 R 컴파일 패키지를 사용하여 바이트 코드를 바이트로 컴파일하는 것입니다.

library(compiler)
repeatedCosPlusOneCompiled <- cmpfun(repeatedCosPlusOne)

결과 함수는 종종 동일한 결과를 반환하면서 훨씬 더 빠릅니다.

all.equal(repeatedCosPlusOne(1, 1e6), repeatedCosPlusOneCompiled(1, 1e6))
# [1] TRUE
system.time(repeatedCosPlusOne(1, 1e6))
#    user  system elapsed 
#   1.175   0.014   1.201 
system.time(repeatedCosPlusOneCompiled(1, 1e6))
#    user  system elapsed 
#   0.339   0.002   0.341 

이 경우 바이트 컴파일은 1.20 초에서 0.34 초까지 길이가 1 백만인 벡터에 대해 터프 투 벡터 라이 제이션 작업을 가속화합니다.

의 본질 repeatedCosPlusOne , 단일 기능의 누적 애플리케이션으로 더욱 투명하게 표현 될 수 Reduce :

iterFunc <- function(init, n, func) {
  funcs <- replicate(n, func)
  Reduce(function(., f) f(.), funcs, init = init, accumulate = TRUE)
}
repeatedCosPlusOne_vec <- function(first, len) {
  iterFunc(first, len - 1, function(.) cos(. + 1))
}

repeatedCosPlusOne_vec 의 "벡터화"으로 간주 될 수있다 repeatedCosPlusOne . 그러나 2 배만큼 느려질 것으로 예상 될 수 있습니다.

library(microbenchmark)
microbenchmark(
  repeatedCosPlusOne(1, 1e4),
  repeatedCosPlusOne_vec(1, 1e4)
)
#> Unit: milliseconds
#>                              expr       min        lq     mean   median       uq      max neval cld
#>      repeatedCosPlusOne(1, 10000)  8.349261  9.216724 10.22715 10.23095 11.10817 14.33763   100  a 
#>  repeatedCosPlusOne_vec(1, 10000) 14.406291 16.236153 17.55571 17.22295 18.59085 24.37059   100   b


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow