如何在没有嵌套 for 循环的情况下快速填充矩阵

How to populate a matrix quickly without nested for loops

我有一个值为 0、1 和 2 的数据集。

data <- matrix(c(1, 0, 0, 1, 2, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 1, 1, 1), nrow = 5, ncol = 4)
> data
     [,1] [,2] [,3] [,4]
[1,]    1    1    0    2
[2,]    0    1    0    0
[3,]    0    0    0    1
[4,]    1    1    0    1
[5,]    2    0    0    1

我想根据这些数据创建一个矩阵,使值 0 为 (0, 0),1 为 (1, 0),2 为 (0, 1)。下面是我正在使用的代码:

data.exp <- matrix(NA, nrow = nrow(data)*2, ncol = ncol(data))
for(i in 1:nrow(data)){
  for(j in 1:(ncol(data))){
    if(data[i,j] == 1){
      vec <- c(1, 0)
    }else if(data[i, j] == 0){
      vec <- c(0, 0)
    }else{
      vec <- c(0, 1)
    }
    data.exp[((i*2-1):(i*2)), j] <- vec
  }
}
> data.exp
      [,1] [,2] [,3] [,4]
 [1,]    1    1    0    0
 [2,]    0    0    0    1
 [3,]    0    1    0    0
 [4,]    0    0    0    0
 [5,]    0    0    0    1
 [6,]    0    0    0    0
 [7,]    1    1    0    1
 [8,]    0    0    0    0
 [9,]    0    0    0    1
[10,]    1    0    0    0

有没有更快的方法来生成矩阵,data.exp,而不必在 R 中使用嵌套的 for 循环?随着样本量的增加,嵌套for循环的方法不是很有效。

apply 对于矩阵来说应该是相当快的。通过将 data 中的 012 作为 v[ 的索引,创建具有适当值和子集的列表 v =18=]

v = list(c(0, 0), c(1, 0), c(0, 1))
apply(data, 2, function(i) do.call(cbind, v[i + 1]))
#       [,1] [,2] [,3] [,4]
#  [1,]    1    1    0    0
#  [2,]    0    0    0    1
#  [3,]    0    1    0    0
#  [4,]    0    0    0    0
#  [5,]    0    0    0    1
#  [6,]    0    0    0    0
#  [7,]    1    1    0    1
#  [8,]    0    0    0    0
#  [9,]    0    0    0    1
# [10,]    1    0    0    0

这是一个没有任何循环的选项

t(
  matrix(
    scan(text = toString(c("0, 0", "1, 0", "0, 1")[data + 1]), sep = ","),
    byrow = TRUE, 
    nrow = ncol(data)
  )
)

这给出了

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

更简洁的选择(感谢@akrun的贡献)

> matrix(unlist(list(c(0, 0), c(1, 0), c(0, 1))[data + 1]), nrow = nrow(data) * 2)
      [,1] [,2] [,3] [,4]
 [1,]    1    1    0    0
 [2,]    0    0    0    1
 [3,]    0    1    0    0
 [4,]    0    0    0    0
 [5,]    0    0    0    1
 [6,]    0    0    0    0
 [7,]    1    1    0    1
 [8,]    0    0    0    0
 [9,]    0    0    0    1
[10,]    1    0    0    0

首先制作两个与数据相同维度的矩阵,一个将所有的2设置为0,另一个将所有的1设置为0,所有的2设置为1。然后将两个矩阵交错一行一行。

第一部分if使用ifelse完成;对于第二部分,flodel's answer to this question 有帮助。

综合起来,你有

data <- matrix(c(1, 0, 0, 1, 2, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 1, 1, 1), nrow = 5, ncol = 4)

l<-list(ifelse(data < 2, data, 0),
     ifelse(data > 1, 1, 0))

do.call(rbind, l)[order(sequence(sapply(l, nrow))), ]

#       [,1] [,2] [,3] [,4]
#  [1,]    1    1    0    0
#  [2,]    0    0    0    1
#  [3,]    0    1    0    0
#  [4,]    0    0    0    0
#  [5,]    0    0    0    1
#  [6,]    0    0    0    0
#  [7,]    1    1    0    1
#  [8,]    0    0    0    0
#  [9,]    0    0    0    1
# [10,]    1    0    0    0