2017-09-27 100 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沒有限制,它可以簡單地創建爲

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

這是非常快的使用data.table。然而,不幸的是,change也可能取決於前一時期的實際value。具體而言,我們假設每當它達到102時,該系列需要在下一個時期到達initial_value並在那裏停留3個時期。因此,在以下的數據幀,我需要創建變量value而上面的代碼產生value0

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 

到目前爲止我設法產生這種結果的唯一方法是使用循環:

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

然而,循環(數十)數以百萬計的觀測數據是非常緩慢的。有沒有一種方法可以對其進行矢量化,或者只是更有效地運行流程?

回答

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更具競爭力:

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循環可以更快地工作。 –