Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create a matrix with a vector of 1 in the diagonal?

Tags:

r

matrix

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?

like image 458
marco.23 Avatar asked Dec 11 '25 01:12

marco.23


2 Answers

Here are some base R options

  • Use kronecker
t(kronecker(diag(390), rep(1, 6)))
  • Use outer
+outer(1:390, rep(1:390, each = 6), `==`)
  • Use [<-
`[<-`(
    matrix(0, nrow = 390, ncol = 390 * 6),
    cbind(rep(1:390, each = 6), seq_len(390 * 6)),
    1
)

Benchmarking

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
like image 55
ThomasIsCoding Avatar answered Dec 12 '25 17:12

ThomasIsCoding


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
like image 45
jblood94 Avatar answered Dec 12 '25 15:12

jblood94