r矩阵单个元素的移位运算

时间:2013-08-16 20:51:32

标签: r matrix shift

我正在尝试优化我编写的一些代码,因为它对于大型数据集来说非常慢。我不确定是否可以通过矩阵运算完成以下操作,如果有人有任何建议可以让它更快,我将不胜感激。

我有一个带有零和整数的矩阵,我想通过条目中整数的绝对数字向下移动各列的条目。

   [,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. 重复下一栏
  5. 谢谢,

    尼科斯

2 个答案:

答案 0 :(得分: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)

答案 1 :(得分: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]