如何在没有嵌套 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
中的 0
、1
或 2
作为 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
我有一个值为 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
中的 0
、1
或 2
作为 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