Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create diagonal matrix of unequal dimensions in r

Tags:

r

matrix

Is there any diag()-like way of creating diagonal matrix of unequal dimensions in r? For instance:

> diag(rep(1,9), nrow=3)
 
1 1 1 0 0 0 0 0 0
0 0 0 1 1 1 0 0 0
0 0 0 0 0 0 1 1 1
like image 400
monotonic Avatar asked Oct 29 '25 02:10

monotonic


2 Answers

Try the Kronecker product

> kronecker(diag(1, 3), t(rep(1, 3)))
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,]    1    1    1    0    0    0    0    0    0
[2,]    0    0    0    1    1    1    0    0    0
[3,]    0    0    0    0    0    0    1    1    1

or shorter and equivalent form with %x%

> diag(1, 3) %x% t(rep(1, 3))
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,]    1    1    1    0    0    0    0    0    0
[2,]    0    0    0    1    1    1    0    0    0
[3,]    0    0    0    0    0    0    1    1    1

Other options might be using tcrossprod + rep

> n <- 3

> +(tcrossprod(rep(1, n), rep(1:n, each = n)) == 1:n)
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,]    1    1    1    0    0    0    0    0    0
[2,]    0    0    0    1    1    1    0    0    0
[3,]    0    0    0    0    0    0    1    1    1

or outer + ==

> n <- 3

> +outer(1:n, rep(1:n, each = n), `==`)
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,]    1    1    1    0    0    0    0    0    0
[2,]    0    0    0    1    1    1    0    0    0
[3,]    0    0    0    0    0    0    1    1    1

Benchmarking

f0 <- function(n) {
    diag(1, n) %x% t(rep(1, n))
}

f1 <- function(n) {
    +(tcrossprod(rep(1, n), rep(1:n, each = n)) == 1:n)
}

f2 <- function(n) {
    +outer(1:n, rep(1:n, each = n), `==`)
}


bm <- function(n) {
    microbenchmark(
        kron = f0(n),
        tprep = f1(n),
        outer = f2(n),
        check = "equivalent",
        unit = "relative"
    )
}

shows

> bm(3)
Unit: relative
  expr       min       lq      mean    median        uq       max neval
  kron 11.895263 11.04810 1.7791532 10.679845 10.037901 0.8851459   100
 tprep  1.000000  1.00000 1.0000000  1.000000  1.000000 1.0000000   100
 outer  2.421579  2.38119 0.9050314  2.363099  2.249479 0.7652963   100

> bm(10)
Unit: relative
  expr      min       lq     mean   median       uq      max neval
  kron 5.306864 5.097848 4.241431 4.915007 4.810881 4.291035   100
 tprep 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000   100
 outer 2.076524 2.017677 1.719520 1.966105 1.929139 1.177178   100

> bm(100)
Unit: relative
  expr      min       lq     mean   median       uq       max neval
  kron 1.194080 1.267156 1.072417 1.318485 1.068942 0.2659374   100
 tprep 1.000000 1.000000 1.000000 1.000000 1.000000 1.0000000   100
 outer 1.583671 1.582495 1.387049 1.445595 1.288268 1.0790626   100
like image 80
ThomasIsCoding Avatar answered Oct 31 '25 17:10

ThomasIsCoding


One more option for generating m by n matrix as described:

m <- 3L
n <- 9L
stopifnot(n>=m, n %% m == 0L)

diag(nrow=m)[, rep(1L:m, each = n %/% m)]

#      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
# [1,]    1    1    1    0    0    0    0    0    0
# [2,]    0    0    0    1    1    1    0    0    0
# [3,]    0    0    0    0    0    0    1    1    1
like image 24
sindri_baldur Avatar answered Oct 31 '25 15:10

sindri_baldur