-2

大規模なデータセットでは非常に遅いため、作成したコードを最適化しようとしています。以下が行列演算で実行できるかどうかはわかりません。誰かがそれを高速化するための提案をしていただければ幸いです。

ゼロと整数を含む行列があり、個々の列のエントリをエントリ内の整数の絶対数だけシフトダウンしたいと考えています。

   [,1] [,2] [,3]
[1,]    0    0    0
[2,]    0   -4    0
[3,]    4    0    0
[4,]   -3   -2    0
[5,]    0    2   -1
[6,]    2   -2    0
[7,]    0    0    0
[8,]   -3   -3    0  

私が使用しているコードは次のとおりです。

#data
A<-matrix(data=c(0,0,4,-3,0,2,0,-3,0,-4,0,-2,2,-2,0,-3,0,0,0,0,-1,0,0,0),nrow=8,ncol=3)

#shift function
shift<-function(x)
{
  #create the output matrix
  out<-matrix(data=0,nrow=8,ncol=1)

  #for loop to create the shift matrix
  for(i in seq(1,8,by=1))
  {
    if(i+abs(x[i])<=8)
    {
      #find the non zero
      if(x[i]!=0)
      {
        #if there is already a number put zero  
        if(out[i+abs(x[i]),1]!=0)
        {
          out[i+abs(x[i]),1]=0
        } else {
          #shift
          out[i+abs(x[i]),1]=x[i]
        }
      }
    }
  }

  #return object
  return(out)
}

#run the logic
shift_mat<-sapply(1:ncol(A),FUN=function(k) shift(A[,k]))

結果は次のとおりです。

   [,1] [,2] [,3]
[1,]    0    0    0
[2,]    0    0    0
[3,]    0    0    0
[4,]    0    0    0
[5,]    0    0    0
[6,]    0    0   -1
[7,]    0    2    0
[8,]    2   -2    0

各列のルールは次のとおりです。

  1. 上から始めて、ゼロ以外の最初のエントリを見つけます
  2. そのエントリの絶対数だけ下にシフトします
  3. 対象のポイントに別のエントリがある場合は、ゼロを入力します
  4. 次の列で繰り返します

ありがとう、

ニコス

4

2 に答える 2

2

シフト演算はベクトル化できます。データの最初の列を見て、次のことを確認しましょう。

v = c(0,0,4,-3,0,2,0,-3)

# index of the elements that could be non-zero in the final result
index = ifelse (v != 0 & abs(v) + seq_along(v) <= length(v),
                abs(v) + seq_along(v), 0)
# [1] 0 0 7 7 0 8 0 0


# now just need to filter out the duplicated entries
index = ave(index, index, FUN = function(x) {if (length(x) > 1) 0 else x})
# [1] 0 0 0 0 0 8 0 0

# home at last
res = integer(length(v))
res[index] = v[which(index != 0)]
res
# [1] 0 0 0 0 0 0 0 2

次に、上記を関数に入れ、次に行列の列またはlapply上に置くことができます。data.frameapply

当然のことながら、上記の最大のボトルネックはave関数であり、その行を次の構造 (どこかにdata.table忘れないでください) に置き換えることで、大幅に高速化できます。require(data.table)

index = data.table(index)[, index := if(.N > 1) 0 else index, by = index][, index]
于 2013-08-16T22:31:37.593 に答える
2

私のマシンであなたの例を使用すると、これは少しきれいになり、約40%高速になります。より大きなデータを使用すると、速度の向上が大きくなるでしょうか?

整数の行列を使用する必要があります。使用するメモリが少なくなり、一部の操作が高速になります。

A <- matrix(as.integer(c(0,0,4,-3,0,2,0,-3,0,-4,0,-2,2,
                        -2,0,-3,0,0,0,0,-1,0,0,0)), nrow = 8, ncol = 3)

各列はベクトルなので、出力になるはずです。行列をベクトルに置き換えました。また、ハードコーディングされた行数なしでコードをより堅牢にしました。

shift <- function(x) {
  n <- length(x)
  y <- rep(0L, n)
  for(i in seq_len(n)) {
    if (x[i] == 0L) next
    j <- i + abs(x[i])
    if (j > n) next
    y[j] <- if (y[j] != 0L) 0L else x[i]
  }
  return(y)
}

次を使用して実行できますapply

shift_mat <- apply(A, 2, shift)
于 2013-08-16T21:26:30.610 に答える