2017-09-27 8 views
8

저는 매우 큰 시계열을 가지고 있으며 처음에는 임의의 값을 기준으로 다른 시계열을 만들고 현재 시간대를 변경해야합니다. 실제 데이터 세트에서 이러한 변화는 데이터 프레임의 다른 변수에 따라 달라 지지만 다음과 같이 MWE의 목적을 위해, 나는 그것을 다시 :R 프로그래밍 : 이전에 계산 된 행을 사용하여 각 행을 업데이트하십시오.

initial_value <- 100 
set.seed(123) 
library(data.table) 
df <- as.data.table(data.frame(num = c(1:10),change = rnorm(10))) 

새로운 변수 value 이전 기간에 자신의 값으로 정의 플러스 현재 기간의 change 첫 번째 관측 값은 임의로 선택한 initial_value에 의해 결정됩니다. value에는 제한이 없다면, 그것은이 매우 빠르게 data.table을 사용

df <- df[, value0 := initial_value + cumsum(change)] 

로 간단하게 만들 수 있습니다. 그러나 불행하게도 change은 이전 기간의 실제 value에 따라 달라질 수 있습니다. 특히, 102에 도달 할 때마다 시리즈는 다음 기간에 initial_value에 도착해야하며 3 기간 동안 거기에 머물러 있어야한다고 가정 해 봅시다.

df$value <- NA 
df$value[1] <- initial_value + df$change[1] 
for (i in 2:nrow(df)) { 
    if (is.na(df$value[i])) { 
    if (df$value[i-1] < 102) { 
     df$value[i] <- df$value[i-1] + df$change[i] 
    } else { 
     df$value[i:(i+2)] <- initial_value 
    } 
    } 
} 
:이 결과를 생성하는 관리

num  change value0  value 
1: 1 -0.56047565 99.43952 99.43952 
2: 2 -0.23017749 99.20935 99.20935 
3: 3 1.55870831 100.76806 100.76806 
4: 4 0.07050839 100.83856 100.83856 
5: 5 0.12928774 100.96785 100.96785 
6: 6 1.71506499 102.68292 102.68292 
7: 7 0.46091621 103.14383 100.00000 
8: 8 -1.26506123 101.87877 100.00000 
9: 9 -0.68685285 101.19192 100.00000 
10: 10 -0.44566197 100.74626 99.55434 

까지 유일한 방법은 루프를 사용한다 : 따라서, 다음 데이터 프레임에서, I 코드가 상기 value0 생산하면서 가변 value을 만들어야

그러나 수십만 회의 관측 루핑은 매우 느립니다. 가능하게 벡터화하거나 더 효율적으로 프로세스를 실행하는 방법이 있습니까?

답변

6

간단한 루프에 Rcpp를 사용하는 것이 좋습니다. 요청 된 논리를 쉽게 복제 할 수 있습니다.
함수 : C++에서

fun_r <- function(){ 
    df$value <- NA 
    df$value[1] <- initial_value + df$change[1] 
    for (i in 2:nrow(df)) { 
    if (is.na(df$value[i])) { 
     if (df$value[i-1] < 102) { 
     df$value[i] <- df$value[i-1] + df$change[i] 
     } else { 
     df$value[i:(i+2)] <- initial_value 
     } 
    } 
    } 
    df 
} 

같은 기능

library(Rcpp) 
cppFunction({' 
    NumericVector fun_c(NumericVector change, double init, double thr){ 
    int n = change.size(); 
    int end; 
    NumericVector out(n); 
    out[ 0 ] = init + change[ 0 ]; 

    for(int i = 1; i < n; i++){ 

    if(out[ i - 1 ] < thr){ 

     out[i] = out[ i - 1 ] + change[ i ]; 

    } else { 

     end = std::min(i + 2 , n - 1); 
     for(int j = i; j <= end; j++) { 
     out[ j ] = init; 
     i = j; 
     } 
    } 

    } 
    return out; 
} 
'}) 

UPDATE : 처음 작성된 R 기능 (위)에 매우 비효율적 인 방법입니다 data.frame 부분 집합에 기반 R. 기능의 데이터를 처리하는 것은 단순히 모든 벤치 마크에서 패배 할 것으로 예상되는 약자입니다. 루핑하는 동안 항상 벡터와 행렬을 계산해야합니다. 함수 아래 Rcpp 예 더 COMPETETIVE있는 :

fun_r2 <- function(change, initial_value, thr){ 
    n <- length(change) 
    value <- numeric(n) 
    value[1] <- initial_value + change[1] 

    for (i in 2:n) { 
    if (value[i]==0) { 
     if (value[i-1] < thr) { 
     value[i] <- value[i-1] + change[i] 
     } else { 
     value[i:(i+2)] <- initial_value 
     } 
    } 
    } 
    value 
} 

세 함수는 동일한 결과를 생성하고, 가장 빠른 fun_c하지만 벡터화 fun_r2 기능이 허용 가능한 것으로 간주 될 수있다.

df$value <- fun_r() 
df$value_r2 <- fun_r2(as.vector(df$change), init=100, thr=102) 
df$value_rcpp <- fun_c(df$change, init=100, thr=102) 

all.equal(df$value, df$value_rcpp) 
all.equal(df$value, df$value_r2) 
# TRUE 

mb <- microbenchmark::microbenchmark(
    fun_r(), 
    fun_r2(as.vector(df$change), init=100, thr=102), 
    fun_c(df$change, init=100, thr=102), 
    times=100L 
) 

# expr  mean 
# 1 fun_r() 6650.72481 
# 2 fun_r2() 42.28442 
# 3 fun_c() 18.24121 

즐기십시오!

+1

놀라워요! 고마워! Rcpp 루프가 훨씬 빠르게 작동한다는 것을 전혀 알지 못했습니다. –