I'm trying to create a diagonal matrix with 390 rows and 2340 columns, but in the diagonal I need to have a vector of 1, rep(1,6).
For example, these should be the first two rows:
1111110.............................0
0000001111110.......................0
How can I do it?
Here are some base R options
kroneckert(kronecker(diag(390), rep(1, 6)))
outer+outer(1:390, rep(1:390, each = 6), `==`)
[<-`[<-`(
matrix(0, nrow = 390, ncol = 390 * 6),
cbind(rep(1:390, each = 6), seq_len(390 * 6)),
1
)
fkron <- function() {
t(kronecker(diag(390), rep(1, 6)))
}
fouter <- function() {
+outer(1:390, rep(1:390, each = 6), `==`)
}
fassign <- function() {
`[<-`(
matrix(0, nrow = 390, ncol = 390 * 6),
cbind(rep(1:390, each = 6), seq_len(390 * 6)),
1
)
}
microbenchmark(
fkron = fkron(),
fouter = fouter(),
fassign = fassign(),
unit = "relative",
check = "equal"
)
shows
Unit: relative
expr min lq mean median uq max neval
fkron 16.315960 6.027245 4.896574 6.471678 4.177969 10.87032 100
fouter 9.802039 3.907079 3.381873 3.964311 2.789494 11.18444 100
fassign 1.000000 1.000000 1.000000 1.000000 1.000000 1.00000 100
Depending on how the matrix is to be used, a sparse matrix may be a better option:
library(Matrix)
x <- sparseMatrix(rep(1:390, each = 6), 1:2340)
Checking
x[1:3, 1:18] # top left
#> 3 x 18 sparse Matrix of class "ngCMatrix"
#>
#> [1,] | | | | | | . . . . . . . . . . . .
#> [2,] . . . . . . | | | | | | . . . . . .
#> [3,] . . . . . . . . . . . . | | | | | |
x[388:390, 2323:2340] # bottom right
#> 3 x 18 sparse Matrix of class "ngCMatrix"
#>
#> [1,] | | | | | | . . . . . . . . . . . .
#> [2,] . . . . . . | | | | | | . . . . . .
#> [3,] . . . . . . . . . . . . | | | | | |
Compared to a dense matrix object, the sparse matrix uses 180 times less memory, is faster to build, and in many cases will speed up operations. Demonstrating:
m <- matrix(rep(1:0, c(6, 2340)), 390, 2340, 1)
object.size(m)
#> 3650616 bytes
object.size(x)
#> 20064 bytes
microbenchmark::microbenchmark(
dense = matrix(rep(1:0, c(6, 2340)), 390, 2340, 1),
sparse = sparseMatrix(rep(1:390, each = 6), 1:2340)
)
#> Unit: microseconds
#> expr min lq mean median uq max neval
#> dense 2176.6 2331.3 3025.947 2510.55 2692.2 12528.5 100
#> sparse 344.3 374.9 546.522 440.85 493.3 10121.5 100
y <- matrix(runif(390*2340), 390, 2340)
microbenchmark::microbenchmark(
dense = crossprod(m, y),
sparse = as.matrix(crossprod(x, y)),
check = "equal",
times = 10,
unit = "relative"
)
#> Unit: relative
#> expr min lq mean median uq max neval
#> dense 121.5391 111.6669 77.11411 82.2131 60.29327 51.23242 10
#> sparse 1.0000 1.0000 1.00000 1.0000 1.00000 1.00000 10
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With