【问题标题】:Cleaner way of constructing binary matrix from vector从向量构造二进制矩阵的更简洁方法
【发布时间】:2014-08-12 18:17:33
【问题描述】:

我有一个有趣的挑战:我正在尝试从一个整数向量构造一个二进制矩阵。二进制矩阵应包含与向量长度一样多的行,以及与整数向量中的最大值一样多的列。矩阵中的第 i 行将对应于向量的第 i 个元素,该行在位置 j 处包含 1,其中 j 等于向量的第 i 个元素的值;否则,该行包含零。如果第 i 个整数的值为 0,那么整个第 i 行应该是 0。

为了让这一切变得更简单,这里有一个可重复的工作示例:

set.seed(1)
playv<-sample(0:5,20,replace=TRUE)#sample integer vector

playmat<-matrix(playv,nrow=length(playv),ncol=max(playv))#create matrix from vector

for (i in 1:length(playv)){
pos<-as.integer(playmat[i,1])
playmat[i,pos]<-1
playmat[i,-pos]<-0}

    head(playmat)
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    0    0    0    0
[2,]    0    1    0    0    0
[3,]    0    0    1    0    0
[4,]    0    0    0    0    1
[5,]    1    0    0    0    0
[6,]    0    0    0    0    1

上面的解决方案是正确的,我只是想让一些东西更健壮。

【问题讨论】:

  • 您在寻找model.matrix吗?
  • t(sapply(playv, function(i) {if (i!=0) {c(rep(0, i-1), 1, rep(0,max(playv)-i))} else rep(0, max(playv))}))

标签: r matrix vector


【解决方案1】:
set.seed(1)
playv <- sample(0:5,20,replace=TRUE)
playv <- as.character(playv)
results <- model.matrix(~playv-1)

result 中的列可以重命名。

我喜欢 Ananda Mahto 提供的解决方案,并将其与 model.matrix 进行了比较。这是一个代码

library(microbenchmark)

set.seed(1)
v <- sample(1:10,1e6,replace=TRUE)

f1 <- function(vec) {
  vec <- as.character(vec)
  model.matrix(~vec-1)
}

f2 <- function(vec) {
  table(sequence(length(vec)), vec)
}

microbenchmark(f1(v), f2(v), times=10)

model.matrixtable 快一点

Unit: seconds
  expr      min       lq   median       uq      max neval
 f1(v) 2.890084 3.147535 3.296186 3.377536 3.667843    10
 f2(v) 4.824832 5.625541 5.757534 5.918329 5.966332    10

【讨论】:

  • 其中一个很难用谷歌搜索,但存在一个非常简单的解决方案。
【解决方案2】:

当然,您也可以只使用table

> table(sequence(length(playv)), playv)
    playv
     0 1 2 3 4 5
  1  0 1 0 0 0 0
  2  0 0 1 0 0 0
  3  0 0 0 1 0 0
  4  0 0 0 0 0 1
  5  0 1 0 0 0 0
  6  0 0 0 0 0 1
  7  0 0 0 0 0 1
  8  0 0 0 1 0 0
  9  0 0 0 1 0 0
  10 1 0 0 0 0 0
  11 0 1 0 0 0 0
  12 0 1 0 0 0 0
  13 0 0 0 0 1 0
  14 0 0 1 0 0 0
  15 0 0 0 0 1 0
  16 0 0 1 0 0 0
  17 0 0 0 0 1 0
  18 0 0 0 0 0 1
  19 0 0 1 0 0 0
  20 0 0 0 0 1 0

如果速度是一个问题,我建议采用手动方法。首先,确定向量中的唯一值。第二,创建一个空矩阵来填充。第三,使用矩阵索引来标识应该填充的位置为1。

像这样:

f3 <- function(vec) {
  U <- sort(unique(vec))
  M <- matrix(0, nrow = length(vec), 
              ncol = length(U), 
              dimnames = list(NULL, U))
  M[cbind(seq_len(length(vec)), match(vec, U))] <- 1L
  M
}

用法为f3(playv)

将其添加到基准测试中,我们得到:

library(microbenchmark)
microbenchmark(f1(v), f2(v), f3(v), times = 10)
# Unit: milliseconds
#   expr       min        lq    median        uq       max neval
#  f1(v) 2104.4808 3151.4308 3314.8173 3344.6696 4023.5246    10
#  f2(v) 3956.5678 4782.7863 5994.4448 6320.1901 6646.0405    10
#  f3(v)  486.4406  574.1133  746.9112  927.3407  987.9121    10

【讨论】:

  • 不错的解决方案!但是比model.matrix慢一点。
  • 我同意在这种情况下速度并不重要。但是,如果一个人使用大型集合,这可能会变得很烦人。如果您能够超越model.matrix,您可以提出您的解决方案来替代model.matrix 功能。 :)
  • 太棒了!我会根据需要使用它。 :)
猜你喜欢
  • 1970-01-01
  • 2011-09-26
  • 2017-11-18
  • 2019-01-07
  • 2019-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多