将二进制向量转换为二进制矩阵

4

我有一个二进制向量,它存储了某些观测事件是否发生的信息:

v <- c(0,1,1,0)

我想要实现的是一个矩阵,它包含有关此向量中所有双变量观测对的信息。也就是说,如果两个观测在向量v中都为0或都为1,则它们应该在矩阵中得到1。如果一个为0,另一个为1,则它们应该得到0,否则得到1。
因此,目标是获得这个矩阵:
     [,1] [,2] [,3] [,4]
[1,]    0    0    0    1
[2,]    0    0    1    0
[3,]    0    1    0    0
[4,]    1    0    0    0

无论主对角线是0或1对我来说都没有关系。
是否存在一种高效简单的方法可以实现这一点,而不需要组合使用if语句和for循环?v可能具有相当大的大小。
谢谢!
4个回答

5
我们可以使用outer
out <- outer(v, v, `==`)
diag(out) <- 0L # as you don't want to compare each element to itself
out
#     [,1] [,2] [,3] [,4]
#[1,]    0    0    0    1
#[2,]    0    0    1    0
#[3,]    0    1    0    0
#[4,]    1    0    0    0

2

expand.grid的另一个选项是创建v与自身的成对组合,由于只有0和1这两个值,所以我们可以找到0和2的值(0 + 0和1 + 1)。

inds <- rowSums(expand.grid(v, v))
matrix(+(inds == 0 | inds == 2), nrow = length(v))


#     [,1] [,2] [,3] [,4]
#[1,]    1    0    0    1
#[2,]    0    1    1    0
#[3,]    0    1    1    0
#[4,]    1    0    0    1

由于对角元素对您来说不重要,因此我将保持其原样,或者如果您想更改,则可以使用diag,如@markus的答案所示。


2

除了使用outer的方法外,还有一种(稍微不太高效)的方法是使用sapply

out <- sapply(v, function(x){
  x == v
})
diag(out) <- 0L
out

     [,1] [,2] [,3] [,4]
[1,]    0    0    0    1
[2,]    0    0    1    0
[3,]    0    1    0    0
[4,]    1    0    0    0

microbenchmark在长度为1000的向量上运行:

> test <- microbenchmark("LAP" = sapply(v, function(x){
+   x == v
+ }),
+ "markus" = outer(v, v, `==`), times = 1000, unit = "ms")
> test
Unit: milliseconds
   expr      min       lq     mean   median       uq       max neval
    LAP 3.973111 4.065555 5.747905 4.573002 6.324607 101.03498  1000
 markus 3.515725 3.535067 4.852606 3.694924 4.908930  84.85184  1000

2
如果允许主对角线为1,则无论v有多大,此矩阵始终会有两个唯一的行v和1-v。由于矩阵是对称的,因此它也具有两个类似的唯一列。这使得构建此矩阵变得微不足道。
## example `v`
set.seed(0)
v <- sample.int(2, 10, replace = TRUE) - 1L
#[1] 1 0 0 1 1 0 1 1 1 1

## column expansion from unique columns
cbind(v, 1 - v, deparse.level = 0L)[, 2 - v]
#      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
# [1,]    1    0    0    1    1    0    1    1    1     1
# [2,]    0    1    1    0    0    1    0    0    0     0
# [3,]    0    1    1    0    0    1    0    0    0     0
# [4,]    1    0    0    1    1    0    1    1    1     1
# [5,]    1    0    0    1    1    0    1    1    1     1
# [6,]    0    1    1    0    0    1    0    0    0     0
# [7,]    1    0    0    1    1    0    1    1    1     1
# [8,]    1    0    0    1    1    0    1    1    1     1
# [9,]    1    0    0    1    1    0    1    1    1     1
#[10,]    1    0    0    1    1    0    1    1    1     1

这个矩阵的目的是什么?
如果有 n0 个零和 n1 个一,那么该矩阵的维度将为 (n0 + n1) x (n0 + n1),但矩阵中只有 (n0 x n0 + n1 x n1) 个一。因此,对于长向量 v,该矩阵是稀疏的。事实上,它具有超级稀疏性,因为它具有大量重复的行/列。
显然,如果要存储该矩阵中 1 的位置,您可以根本不需要形成该矩阵。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接