使用矩阵值作为索引
Use matrix values as indices
我正在进行 Fisher 排列检验,其中我必须生成治疗状态的所有组合。
我们有 4 名受试者,其中 2 名接受治疗。使用 combn
,我可以生成治疗对象的所有组合。例如,第一行表示治疗了第一和第二个受试者。
t(combn(4, 2))
[,1] [,2]
[1,] 1 2
[2,] 1 3
[3,] 1 4
[4,] 2 3
[5,] 2 4
[6,] 3 4
如何从这个矩阵转到治疗状态矩阵,如下所示:
[,1] [,2] [,3] [,4]
[1,] 1 1 0 0
[2,] 1 0 1 0
...
使用 base-R:
res <- t(apply(t(combn(4,2)),MARGIN=1,FUN=function(x){
return(as.numeric(1:4 %in% x))
}))
> res
[,1] [,2] [,3] [,4]
[1,] 1 1 0 0
[2,] 1 0 1 0
[3,] 1 0 0 1
[4,] 0 1 1 0
[5,] 0 1 0 1
[6,] 0 0 1 1
怎么样:
out <- matrix(0L, nrow = nrow(x), ncol = max(x))
for (i in 1:nrow(x)) out[i, x[i, ]] <- 1L
> out
[,1] [,2] [,3] [,4]
[1,] 1 1 0 0
[2,] 1 0 1 0
[3,] 1 0 0 1
[4,] 0 1 1 0
[5,] 0 1 0 1
[6,] 0 0 1 1
我们也可以不使用循环来执行此操作,尽管它的可读性可能会差一些(感谢@Frank 的步法):
m <- matrix(0L, choose(4, 2), 4)
m[cbind(rep(1:choose(4, 2), each = 2), c(combn(4, 2)))] <- 1L
轻松包装到函数中:
participants <- function(m, n){
if (n > m) stop( )
mcn <- choose(m, n)
out <- matrix(0L, mcn, m)
out[cbind(rep(1:mcn, each = n), c(combn(m, n)))] <- 1L
out
}
> participants(6, 5)
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 1 1 1 1 0
[2,] 1 1 1 1 0 1
[3,] 1 1 1 0 1 1
[4,] 1 1 0 1 1 1
[5,] 1 0 1 1 1 1
[6,] 0 1 1 1 1 1
发表我的评论作为解决方案。这是对@Heroka 的建议的修改。 +
会将 logical
转换为 numeric
并且应该比 as.integer
.
更快
+(t(combn(4,2, FUN=function(x) 1:4 %in% x)))
# [,1] [,2] [,3] [,4]
#[1,] 1 1 0 0
#[2,] 1 0 1 0
#[3,] 1 0 0 1
#[4,] 0 1 1 0
#[5,] 0 1 0 1
#[6,] 0 0 1 1
我正在进行 Fisher 排列检验,其中我必须生成治疗状态的所有组合。
我们有 4 名受试者,其中 2 名接受治疗。使用 combn
,我可以生成治疗对象的所有组合。例如,第一行表示治疗了第一和第二个受试者。
t(combn(4, 2))
[,1] [,2]
[1,] 1 2
[2,] 1 3
[3,] 1 4
[4,] 2 3
[5,] 2 4
[6,] 3 4
如何从这个矩阵转到治疗状态矩阵,如下所示:
[,1] [,2] [,3] [,4]
[1,] 1 1 0 0
[2,] 1 0 1 0
...
使用 base-R:
res <- t(apply(t(combn(4,2)),MARGIN=1,FUN=function(x){
return(as.numeric(1:4 %in% x))
}))
> res
[,1] [,2] [,3] [,4]
[1,] 1 1 0 0
[2,] 1 0 1 0
[3,] 1 0 0 1
[4,] 0 1 1 0
[5,] 0 1 0 1
[6,] 0 0 1 1
怎么样:
out <- matrix(0L, nrow = nrow(x), ncol = max(x))
for (i in 1:nrow(x)) out[i, x[i, ]] <- 1L
> out
[,1] [,2] [,3] [,4]
[1,] 1 1 0 0
[2,] 1 0 1 0
[3,] 1 0 0 1
[4,] 0 1 1 0
[5,] 0 1 0 1
[6,] 0 0 1 1
我们也可以不使用循环来执行此操作,尽管它的可读性可能会差一些(感谢@Frank 的步法):
m <- matrix(0L, choose(4, 2), 4)
m[cbind(rep(1:choose(4, 2), each = 2), c(combn(4, 2)))] <- 1L
轻松包装到函数中:
participants <- function(m, n){
if (n > m) stop( )
mcn <- choose(m, n)
out <- matrix(0L, mcn, m)
out[cbind(rep(1:mcn, each = n), c(combn(m, n)))] <- 1L
out
}
> participants(6, 5)
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 1 1 1 1 0
[2,] 1 1 1 1 0 1
[3,] 1 1 1 0 1 1
[4,] 1 1 0 1 1 1
[5,] 1 0 1 1 1 1
[6,] 0 1 1 1 1 1
发表我的评论作为解决方案。这是对@Heroka 的建议的修改。 +
会将 logical
转换为 numeric
并且应该比 as.integer
.
+(t(combn(4,2, FUN=function(x) 1:4 %in% x)))
# [,1] [,2] [,3] [,4]
#[1,] 1 1 0 0
#[2,] 1 0 1 0
#[3,] 1 0 0 1
#[4,] 0 1 1 0
#[5,] 0 1 0 1
#[6,] 0 0 1 1