2017-05-18 6 views
0

大きな行列/データフレーム(2500x20)を持っていて、現在のものを除く、すべての前のセルの最小値から最大値までのローリング偏差が必要です。R:行列上の絶対ローリング偏差(オフセット1)

私の機能は列で適用されます。私の関数は、列全体を(ベクトルとして)1:長さだけシフトし、リストのリストを生成します。 max(x)-min(x)関数を適用するには行列としてこれを必要とします。これは小さな行列のために働き、必要なサイズには長すぎます。

(小)ソース(付属):

 [,1] [,2] [,3] [,4] [,5] 
[1,] 55 9 99 0 NA 
[2,] 54 7 98 1 NA 
[3,] 56 12 97 2 NA 
[4,] 53 8 96 3 1 
[5,] 57 22 95 4 0 
[6,] 52 51 94 5 -1 
[7,] 58 6 93 6 NA 
[8,] 51 6 93 7 0 
[9,] 59 51 92 8 2 
[10,] 50 78 91 9 NA 
[11,] 60 12 90 10 NA 
[12,] 49 5 89 11 -2 

期待結果:それはから計算することができる以前の行を持っていないので

 [,1] [,2] [,3] [,4] [,5] 
[1,] 0 0 0 0 0 
[2,] 0 0 0 0 0 
[3,] 1 2 1 1 0 
[4,] 2 5 2 2 0 
[5,] 3 5 3 3 0 
[6,] 4 15 4 4 1 
[7,] 5 44 5 5 2 
[8,] 6 45 6 6 2 
[9,] 7 45 6 7 2 
[10,] 8 45 7 8 3 
[11,] 9 72 8 9 3 
[12,] 10 72 9 10 3 

最初の結果行は常に0になります。
2つ目の結果行は、1つ前の行が最大値と最小値であるため、常にゼロになります。
最後のsource-rowは決して結果に影響しません。私がこれまで持って何

library(data.table) 

mytest <- matrix(c(
55, 9,99, 0,NA, 
54, 7,98, 1,NA, 
56,12,97, 2,NA, 
53, 8,96, 3, 1, 
57,22,95, 4, 0, 
52,51,94, 5,-1, 
58, 6,93, 6,NA, 
51, 6,93, 7, 0, 
59,51,92, 8, 2, 
50,78,91, 9,NA, 
60,12,90,10,NA, 
49, 5,89,11,-2 
), ncol=5, byrow = TRUE) 

rolling_deviation <- function (a_column){ 
    tmp1 = shift(a_column, 1:(length(a_column)-1), NA, "lag") 
    tmp2 = matrix(unlist(tmp1), ncol = length(a_column), byrow = TRUE) 
    apply(tmp2,2,function(x){ 
     x = x[!is.na(x)] 
     ifelse(length(x)==0, 0, max(x) - min(x)) 
    }) 
} 

apply(mytest,2,rolling_deviation) 

私は、観測が増加するにつれてより多くの行があるでしょう、より速く計算するために、これを必要とします。

+0

あなたはコードに(data.table) – akrun

+0

申し訳ありませんが、追加のライブラリを使用するパッケージを指定する必要があるかもしれません - 私はシフトを見落とし。 –

答えて

0

これはいかがですか?

> system.time(outcome<- apply(mytest,2,rolling_deviation)) 
    user system elapsed 
    0.014 0.002 0.038 

> system.time(outcome1<- setDT(data.frame(mytest))[, lapply(.SD, rolling_deviation)]) 
    user system elapsed 
    0.002 0.000 0.002 

結果は同じです。

> outcome 
     [,1] [,2] [,3] [,4] [,5] 
[1,] 0 0 0 0 0 
[2,] 0 0 0 0 0 
[3,] 1 2 1 1 0 
[4,] 2 5 2 2 0 
[5,] 3 5 3 3 0 
[6,] 4 15 4 4 1 
[7,] 5 44 5 5 2 
[8,] 6 45 6 6 2 
[9,] 7 45 6 7 2 
[10,] 8 45 7 8 3 
[11,] 9 72 8 9 3 
[12,] 10 72 9 10 3 

> outcome1 
    X1 X2 X3 X4 X5 
1: 0 0 0 0 0 
2: 0 0 0 0 0 
3: 1 2 1 1 0 
4: 2 5 2 2 0 
5: 3 5 3 3 0 
6: 4 15 4 4 1 
7: 5 44 5 5 2 
8: 6 45 6 6 2 
9: 7 45 6 7 2 
10: 8 45 7 8 3 
11: 9 72 8 9 3 
12: 10 72 9 10 3 
+0

残念ながら、これは2500x20のデータには影響しません –

0

私は、ネストされたループを作成することによって、私の問題を解決しました。私は、ループに頼ることは、ほとんどの場合、パフォーマンスにとって悪いことになると教えられましたが、私はより良い方法を見つけることができません。 NAの引数は可能性があり、私の目的にとってはエラーではないので、最小/最大操作のヘルパー関数が必要です。

rolling_range <- function(in_mat){ 
    ignore_na = function(op, a,b){ 
     if(is.na(a)){ 
      return(b) 
     }else if(is.na(b)){ 
      return(a) 
     }else{ 
      return(op(a,b)) 
     } 
    } 
    out_mat.min = matrix(NA, nrow = nrow(in_mat), ncol = ncol(in_mat)) 
    out_mat.max = matrix(NA, nrow = nrow(in_mat), ncol = ncol(in_mat)) 
    out_mat.result = matrix(0, nrow = nrow(in_mat), ncol = ncol(in_mat)) 
    for(m in 1:ncol(in_mat)){ 
     for(n in 2:nrow(in_mat)){ 
      out_mat.min[n,m] = ignore_na(`min`, out_mat.min[(n-1),m], in_mat[(n-1),m]) 
      out_mat.max[n,m] = ignore_na(`max`, out_mat.max[(n-1),m], in_mat[(n-1),m]) 
      out_mat.result[n,m] = ifelse(is.na(out_mat.min[n,m]) || is.na(out_mat.max[n,m]), 0, out_mat.max[n,m] - out_mat.min[n,m]) 
     } 
    } 
    return(out_mat.result) 
} 

rolling_range(mytest)