is it possible to have a matrix of matrices in R? - r

is it possible to have a matrix of matrices in R? if yes, how should I define such matrix?
for example to have a 10 x 10 matrix, and each element of this matrix contains a matrix itself.

1) list/matrix Yes, create a list and give it dimensions using matrix:
m <- matrix(1:4, 2)
M <- matrix(list(m, 2*m, 3*m, 4*m), 2)
so element 1,1 of M is m:
> M[[1,1]]
[,1] [,2]
[1,] 1 3
[2,] 2 4
2) list/dim<- This also works:
M <- list(m, 2*m, 3*m, 4*m)
dim(M) <- c(2, 2)
3) array This is not quite what you asked for but depending on your purpose it might satisfy your need:
A <- array(c(m, 2*m, 3*m, 4*m), c(2, 2, 2, 2)) # 2x2x2x2 array
so element 1,1 is:
> A[1,1,,]
[,1] [,2]
[1,] 1 3
[2,] 2 4

Related

Generate square symmetric matrix in R

I have a matrix in R as follows:
dat <- matrix(c(2,3,5,7,8,4), ncol = 6)
colnames(dat) <- c("A(1,1)", "A(1,2)", "A(1,3)", "A(2,2)", "A(2,3)", "A(3,3)")
How can I create a square symmetric matrix based on an apply function that has the following form:
A(1,1) A(1,2) A(1,3)
A(2,1) A(2,2) A(2,3)
A(3,1) A(3,2) A(3,3)
Note that A(1,2)=A(2,1)
This isn't based on apply but it shows how you can use lower.tri and upper.tri to create a symmetric matrix given a vector of elements. It shows the 3x3 case, but will easily generalize to larger n:
dat <- matrix(rep(0,9),nrow = 3)
dat[lower.tri(dat,diag = TRUE)] <- c(2,3,5,7,8,4)
dat[upper.tri(dat)] <- t(dat)[upper.tri(dat)]
print(dat)
Result:
[,1] [,2] [,3]
[1,] 2 3 5
[2,] 3 7 8
[3,] 5 8 4

Matrix Multiplication along specified array dimension with R/Rcpp

Given an n dimensional array X, a d by d-1 dimensional matrix V and two specified dimensions (p1, p2) <= (n, n); I would like a function that preforms matrix multiplication of V along the dimensions (p1, p2) of X.
That is given X:
library(abind)
set.seed(4)
X <- matrix(runif(4), 2, 2)
X <- abind(x, x+5, along = 3)
> a
, , 1
[,1] [,2]
[1,] 1 3
[2,] 2 4
, , 2
[,1] [,2]
[1,] 6 8
[2,] 7 9
and given a matrix V
V <- matrix(c(1, 2))
[,1]
[1,] 1
[2,] 2
For example, if p1=2 and p2=1 I would like to remove the following for loop
p1 <- 1
p2 <- 2
a.out <- array(0, c(2, 1, 2))
for (i in 1:dim(a)[2]){
a.out[,,i] <- a[,,i]%*%V # note indexed along other dimension
}
> a.out
, , 1
[,1]
[1,] 7
[2,] 10
, , 2
[,1]
[1,] 22
[2,] 25
The hard part here is that I want to allow for arbitrary dimensional arrays (i.e., n could be greater than 3).
1st Edit:
This problem is not the same as Indexing slice from 3D Rcpp NumericVector as I am discussing arbitrary number of dimensions >=2 and the question is not only about indexing.
2nd Edit:
Just to be a little more clear here is another example of what I am trying to do. Here the dimension of X is 4, p1 = 2, p3=3, and the dimension of X along the p1 dimension is 12. The following code computes the desired result as X.out for random X and V.
X <- array(rnorm(672), c(4, 7, 12, 2))
V <- matrix(rnorm(132), 12, 11) # p1 = 2, p2 = 3, V is of dimension D x D-1
d <- dim(X)
X.out <- array(0, dim=c(d[1:2], d[3]-1, d[4]))
for(i in 1:d[1]){
for (j in 1:d[4]){
X.out[i,,,j] <- X[i,,,j]%*%V # p1 = 2, p2 = 3
}
}

Outer function R - maintain coordinate subtraction

I have two matrices, call them A (n x 2) and B (q x 2). I'd like to get an n x q x 2 array C, such that C[1,5,] represents the difference between the first row of A and the fifth row of B, taking the subtraction of the first element in the first row of A with the first element in the fifth row of B and the second element similarly subtracted.
I'm trying to perform this function via the outer function, but it also gives me the "non-diagonal" subtractions; i.e. it will also subtract A[1,1] - B[5,2] and A[1,2] - B[5,1] which I am not interested in. Does anyone have a fast, easy way to do this?
Current code
>diffs <- outer(A,B,FUN ='-')
>diffs[1,,5,]
[,1] [,2]
[1,] **-0.3808701** 0.7591052
[2,] 0.2629293 **1.4029046**
I've added the stars to indicate what I actually want.
Thanks for any help in advance
(EDIT)
Here's a simpler case for illustrative purposes
> A <- matrix(1:10, nrow = 5, ncol = 2)
> B <- matrix(4:9, nrow = 3, ncol = 2)
> A
[,1] [,2]
[1,] 1 6
[2,] 2 7
[3,] 3 8
[4,] 4 9
[5,] 5 10
> B
[,1] [,2]
[1,] 4 7
[2,] 5 8
[3,] 6 9
>diffs <- outer(A,B,FUN ='-')
>diffs[1,,3,] == (A[1,] - B[3,])
[,1] [,2]
[1,] TRUE FALSE
[2,] FALSE TRUE
>diffs[1,,3,]
[,1] [,2]
[1,] -5 -8
[2,] 0 -3
Before worrying about the shape of the output I think we should make sure we're getting the correct values.
A <- matrix(1:10, nrow=5, ncol=2)
B <- matrix(4:9, nrow=3, ncol=2)
# long-winded method
dia_long <- c(
c(A[1,] - B[1,]),
c(A[1,] - B[2,]),
c(A[1,] - B[3,]),
c(A[2,] - B[1,]),
c(A[2,] - B[2,]),
c(A[2,] - B[3,]),
c(A[3,] - B[1,]),
c(A[3,] - B[2,]),
c(A[3,] - B[3,]),
c(A[4,] - B[1,]),
c(A[4,] - B[2,]),
c(A[4,] - B[3,]),
c(A[5,] - B[1,]),
c(A[5,] - B[2,]),
c(A[5,] - B[3,]))
# loop method
comb <- expand.grid(1:nrow(A), 1:nrow(B))
dia_loop <- list()
for (i in 1:nrow(comb)) {
dia_loop[[i]] <- A[comb[i, 1], ] - B[comb[i, 2], ]
}
dia_loop <- unlist(dia_loop)
# outer/apply method
dia_outer <- apply(outer(A, B, FUN='-'), c(3, 1), diag)
# they all return the same values
all.identical <- function(l) {
all(sapply(2:length(l), FUN=function(x) identical(l[1], l[x])))
}
all.identical(lapply(list(dia_long, dia_loop, dia_outer), sort))
# TRUE
table(dia_long)
# dia_long
# -5 -4 -3 -2 -1 0 1 2 3
# 1 2 4 5 6 5 4 2 1
Are these the values you are looking for?
My solution: use nested lapply and sapply functions to extract the diagonals. I then needed to do some post-processing (not related to this specific problem), before I then turned it into an array. Should be noted that this is a q x 2 x n array, which turned out to be better for my purposes - this could be permuted with aperm from here though to solve the original question.
A <- matrix(1:10, nrow = 5, ncol = 2)
B <- matrix(4:9, nrow = 3, ncol = 2)
diffs <- outer(A,B, FUN = '-')
diffs <- lapply(X = 1:nrow(A),FUN = function(y){
t(sapply(1:ncol(B), FUN = function(x) diag(diffs[y,,x,])))})
diffs <- array(unlist(lapply(diffs, FUN = t)), dim = c(nrow(B),2,nrow(A)))

Add coefficients of a vector to a matrix

I would like to add each coefficient of a vector to each different column of a matrix. For example, if I have a vector and a matrix:
x <- c(1,2,3)
M <- matrix(c(5,6,7), nrow = 3, ncol = 3)
I would like to in my new matrix M1 1+5 in the first column, 2+6 in the second and 3+7 in the last one.
Is there any function in R that does this task?
try this:
M + rep(x, each = nrow(M))
or this:
apply(M, 1, `+`, x)
result:
[,1] [,2] [,3]
[1,] 6 7 8
[2,] 7 8 9
[3,] 8 9 10
EDIT:
akrun commented on two other great solutions:
M + x[col(M)]
and
sweep(M, 2, x, "+")

Get rank of matrix entries?

Assume a matrix:
> a <- matrix(c(100, 90, 80, 20), 2, 2)
> a
[,1] [,2]
[1,] 100 80
[2,] 90 20
Suppose I want to convert the elements of the matrix to ranks:
>rank.a <- rank(a)
> rank.a
[1] 4 3 2 1
This returns a vector, i.e. the matrix structure is lost. Is it possible to rank a matrix such that the output will be of the form:
[,1] [,2]
[1,] 4 2
[2,] 3 1
An alternative to #EDi's Answer is to copy a and then assign the output of rank(a) directly into the elements of the copy of a:
> a <- matrix(c(100, 90, 80, 20), 2, 2)
> rank.a <- a
> rank.a[] <- rank(a)
> rank.a
[,1] [,2]
[1,] 4 2
[2,] 3 1
That saves you from rebuilding a matrix by interrogating the dimensions of the input matrix.
Note that (as #Andrie mentions in the comments) the copying of a is only required if one wants to keep the original a. The main point to note is that because a is already of the appropriate dimensions, we can treat it like a vector and replace the contents of a with the vector of ranks of a.
why not convert the vector back to a matrix, with the dimensions of the original matrix?
> a <- matrix(c(100, 90, 80, 20, 10, 5), 2, 3)
> a
[,1] [,2] [,3]
[1,] 100 80 10
[2,] 90 20 5
> rank(a)
[1] 6 5 4 3 2 1
> rmat <- matrix(rank(a), nrow = dim(a)[1], ncol = dim(a)[2])
> rmat
[,1] [,2] [,3]
[1,] 6 4 2
[2,] 5 3 1
#Gavin Simpson has a very nice and elegant solution! But there is one caveat though:
The type of the matrix will stay the same or be widened. Mostly you wouldn't notice, but consider the following:
a <- matrix( sample(letters, 4), 2, 2)
rank.a <- a
rank.a[] <- rank(a)
typeof(rank.a) # character
Since the matrix was character to start with, the rank values (which are doubles) got coerced into character strings!
Here's a safer way that simply copies all the attributes:
a <- matrix( sample(letters, 4), 2, 2)
rank.a <- rank(a)
attributes(rank.a) <- attributes(a)
typeof(rank.a) # double
Or, as a one-liner using structure to copy only the relevant attributes (but more typing):
a <- matrix( sample(letters, 4), 2, 2)
rank.a <- structure(rank(a), dim=dim(a), dimnames=dimnames(a))
Of course, dimnames could be left out in this particular case.

Resources