如何从列索引向量中向量化扩展压缩稀疏矩阵?

How to vectorize expanding a compressed sparse matrix from vector of column indices?

我想从向量构建一个矩阵如下:如果y的第一个元素是5,我想使矩阵的第一行和第5列为1。行中的其他元素为0。

y=round(runif(30)*9)+1
y_m=matrix(rep(0,length(y)*10),ncol=10)
for (i in 1:length(y)){
  y_m[i,y[i]]=1;
}

有什么办法可以避免for循环吗?我试图做 y_m[,y]=1 但显然它不起作用。

您可以使用:

y_m[cbind(1:length(y), y)] <- 1

由于您有一个稀疏矩阵,您可能需要:

sparse_y_m <- Matrix::sparseMatrix(i = 1:length(y), j = y, x = 1)

如果你想要一个完整的矩阵,使用

y_m <- as.matrix(sparse_y_m)

是:使用两列索引矩阵。来自 ?"[":

When indexing arrays by ‘[’ a single argument ‘i’ can be a matrix with as many columns as there are dimensions of ‘x’; the result is then a vector with elements corresponding to the sets of indices in each row of ‘i’.

设置:

set.seed(101)
y <- round(runif(30)*9)+1

你的方式(我稍微简化了矩阵构造):

y_m <- matrix(0,ncol=10,nrow=length(y))
for (i in 1:length(y)){
  y_m[i,y[i]] <- 1
}

通过矩阵索引:

y_m2 <- matrix(0,ncol=10,nrow=length(y))
y_m2[cbind(1:length(y),y)] <- 1

检查:

all.equal(y_m,y_m2)  ## TRUE

您可以使用 xtabs 仅从 y 生成矩阵,通过行号索引传播 1 的向量,即 seq_along(y) 然后 y本身:

xtabs(rep(1, length(y)) ~ seq_along(y) + y)
##             y
## seq_along(y) 1 2 3 4 5 6 7 8 9 10
##           1  0 0 0 1 0 0 0 0 0  0
##           2  0 1 0 0 0 0 0 0 0  0
##           3  1 0 0 0 0 0 0 0 0  0
##           4  0 0 0 0 0 0 1 0 0  0
##           5  0 0 0 1 0 0 0 0 0  0
##           6  0 0 0 1 0 0 0 0 0  0
##           ...

或将其设为稀疏矩阵:

xtabs(rep(1, length(y)) ~ seq_along(y) + y, sparse = TRUE)
## 30 x 10 sparse Matrix of class "dgCMatrix"
##                       
## 1  . . . 1 . . . . . .
## 2  . 1 . . . . . . . .
## 3  1 . . . . . . . . .
## 4  . . . . . . 1 . . .
## 5  . . . 1 . . . . . .
## 6  . . . 1 . . . . . .
## ...

或使用 data.frame 设置以获得更好的标签:

xtabs(i ~ row + y, data.frame(y, i = 1, row = seq_along(y)))
##     y
## row  1 2 3 4 5 6 7 8 9 10
##   1  0 0 0 1 0 0 0 0 0  0
##   2  0 1 0 0 0 0 0 0 0  0
##   3  1 0 0 0 0 0 0 0 0  0
##   4  0 0 0 0 0 0 1 0 0  0
##   5  0 0 0 1 0 0 0 0 0  0
##   6  0 0 0 1 0 0 0 0 0  0
##   ...