R:如何在没有 for 循环的情况下分配 A[B[ j], j]
R: how to assign A[B[, j], j] without for-loop
我想用另一个值替换矩阵 A
中的某些值:在本例中为 1
。对于 A
的第 j 列,需要替换的行索引是 B
的第 jth 列中的行索引。下面我举个例子,赋值是通过for循环实现的。
我的问题是:如何在没有 for 循环的情况下更简单、更高效地完成这项任务?
set.seed(4521)
n <- 10
p <- 5
A <- matrix(rep(NaN,n*p),n,p)
B <- replicate(p, sample(n))
B <- B[1:5,]
for (j in 1:n){
A[B[,j],j] <- 1
}
print(B)
print(A)
B
:
[,1] [,2] [,3] [,4] [,5]
[1,] 5 10 7 6 5
[2,] 10 2 9 9 2
[3,] 7 9 3 10 4
[4,] 9 4 1 3 3
[5,] 4 8 6 4 9
A
:
[,1] [,2] [,3] [,4] [,5]
[1,] NaN NaN 1 NaN NaN
[2,] NaN 1 NaN NaN 1
[3,] NaN NaN 1 1 1
[4,] 1 1 NaN 1 1
[5,] 1 NaN NaN NaN 1
[6,] NaN NaN 1 1 NaN
[7,] 1 NaN 1 NaN NaN
[8,] NaN 1 NaN NaN NaN
[9,] 1 1 1 1 1
[10,] 1 1 NaN 1 NaN
我们可以使用矩阵索引:
i <- as.numeric(B)
j <- rep(1:ncol(B), each = nrow(B))
A[cbind(i,j)] <- 1
或者将它们放在一行中:
A[cbind(as.numeric(B), rep(1:ncol(B), each = nrow(B)))] <- 1
正如 OP 后来被一些深入挖掘的人指出的那样,我们可以用更短的 as.numeric(col(B))
替换 rep(1:ncol(B), each = nrow(B))
。我知道,但我从来没有这样做过,因为它使用的内存是我建议的内存的两倍。使用哪一个只是个人喜好。它仅在处理大型矩阵时才重要。
恕我直言,@Zheyuan Li 的代码在做什么更清楚。我更喜欢他的解决方案。
只是为了展示一个替代方案:使用 1D 索引你可以这样做:
An <- nrow(A)
Bp <- ncol(B)
offset <- rep(seq(0, An*(Bp-1), by=An), each=Bp)
A[B + offset] <- 1
一行:
A[B + rep(seq(0, nrow(A)*(ncol(B)-1), by=nrow(A)), each=ncol(B))] <- 1
简单的解决方案:
A[cbind(as.numeric(B), as.numeric(col(B)))] <- 1
感谢(并 +1)李哲元第一个答案中的错字,其中 col
而不是 ncol
。
我想用另一个值替换矩阵 A
中的某些值:在本例中为 1
。对于 A
的第 j 列,需要替换的行索引是 B
的第 jth 列中的行索引。下面我举个例子,赋值是通过for循环实现的。
我的问题是:如何在没有 for 循环的情况下更简单、更高效地完成这项任务?
set.seed(4521)
n <- 10
p <- 5
A <- matrix(rep(NaN,n*p),n,p)
B <- replicate(p, sample(n))
B <- B[1:5,]
for (j in 1:n){
A[B[,j],j] <- 1
}
print(B)
print(A)
B
:
[,1] [,2] [,3] [,4] [,5]
[1,] 5 10 7 6 5
[2,] 10 2 9 9 2
[3,] 7 9 3 10 4
[4,] 9 4 1 3 3
[5,] 4 8 6 4 9
A
:
[,1] [,2] [,3] [,4] [,5]
[1,] NaN NaN 1 NaN NaN
[2,] NaN 1 NaN NaN 1
[3,] NaN NaN 1 1 1
[4,] 1 1 NaN 1 1
[5,] 1 NaN NaN NaN 1
[6,] NaN NaN 1 1 NaN
[7,] 1 NaN 1 NaN NaN
[8,] NaN 1 NaN NaN NaN
[9,] 1 1 1 1 1
[10,] 1 1 NaN 1 NaN
我们可以使用矩阵索引:
i <- as.numeric(B)
j <- rep(1:ncol(B), each = nrow(B))
A[cbind(i,j)] <- 1
或者将它们放在一行中:
A[cbind(as.numeric(B), rep(1:ncol(B), each = nrow(B)))] <- 1
正如 OP 后来被一些深入挖掘的人指出的那样,我们可以用更短的 as.numeric(col(B))
替换 rep(1:ncol(B), each = nrow(B))
。我知道,但我从来没有这样做过,因为它使用的内存是我建议的内存的两倍。使用哪一个只是个人喜好。它仅在处理大型矩阵时才重要。
恕我直言,@Zheyuan Li 的代码在做什么更清楚。我更喜欢他的解决方案。
只是为了展示一个替代方案:使用 1D 索引你可以这样做:
An <- nrow(A)
Bp <- ncol(B)
offset <- rep(seq(0, An*(Bp-1), by=An), each=Bp)
A[B + offset] <- 1
一行:
A[B + rep(seq(0, nrow(A)*(ncol(B)-1), by=nrow(A)), each=ncol(B))] <- 1
简单的解决方案:
A[cbind(as.numeric(B), as.numeric(col(B)))] <- 1
感谢(并 +1)李哲元第一个答案中的错字,其中 col
而不是 ncol
。