matrix of matrices (as a list) in R - r

Suppose I have 3 matrices C,W, and S
C <- matrix(1:3)
W <- matrix(2:4)
S <- matrix(3:5)
I want to make a matrix with those matrices as elements. Say matrix K, but each element of matrix K being a matrix itself. Just as a list of matrices works, but instead in a matrix form. I.e.:
> K
[,1] [,2] [,3]
[1,] C 0 0
[2,] 0 W S
C, W and S would each be matrix objects stored inside the larger matrix K.
Ultimately, I would like to be able to then use matrix multiplication like K %*% K or similar.

There are not a lot of classes than can be an element in an R matrix. In particular objects that rely on attributes for their behavior cannot be objects that will retain their essential features. And ironically that includes matrices themselves since their behavior is governed by the dim(ension) attribute. That exclusion applies to dates, factors and specialized lists such as dataframes. You can include lists as index-able items in a matrix, but as #thelatemail's comment points out this will be somewhat clunky.
> C <- matrix(0, 3,2)
> W <- matrix(1, 4,5)
> S <- matrix(2, 6,7)
> bigM <- matrix( list(), 2, 3)
> bigM[1,1] <- list(C)
> bigM[2,2] <- list(W)
> bigM[2,3] <- list(S)
> bigM
[,1] [,2] [,3]
[1,] Numeric,6 NULL NULL
[2,] NULL Numeric,20 Numeric,42
> bigM[2,3][[1]][42]
[1] 2
Notice the need to extract the matrix itself with [[1]] after extracting it as a list with [2,3]. It's only after that additonal step thay you can get the 42nd item in the matrix, whould alos have been the [6,7]th item if you chose to reference it by row,column indices.

Related

Multiply a matrix' columns by its columns

I have a 4x100 matrix where I would like to multiply column 1 with row 1 in its transpose etc and store these matrices somewhere to be able to take the sum of these new matrices lateron.
I really don't know where to start due to the fact that I get 4x4 matrices after the column-row-multiplication. Due to this fact I cannot store them in a matrix
data:
mm num[1:4,1:100]
mm_t num[1:100,1:4]
I'm thinking of creating a list in some way
list1=list()
for(i in 1:100){
list1[i] <- mm[,i]%*%mm_t[i,]
}
but I need some more indices i think because this just leaves me with a number in each argument..
First, your call for data is not clear. Second, are you tryign to multiply each value by itself, or do matrix multiplication
We create a 4x100 matrix and its transpose:
mm <- matrix(1:400, nrow = 4, ncol = 100)
mm.t <- t(mm)
Then we can do the matrix multiplication (which is what you did, and you get a 4 x 4 matrix from the definition of matrix multiplication https://www.wikiwand.com/en/Matrix_multiplication)
If we want to multiply each index by itself (so mm[1,1] by mm [1,1]) then:
mm * mm
This will result in 4x100 matrix where each value is the square of the original value.
If we want the matrix multiplication of each column with itself, then:
sapply(1:100, function(x) {
mm[, x] %*% mm[, x]
})
This results in 100 values: each one is the matrix product of a 4x1 vector with itself.
Let's start with some sample data. Please get in the habit of including things like this in your question:
nr = 4
nc = 100
set.seed(47)
mm = matrix(runif(nr * nc), nrow = nr)
Here's a working answer, very similar to your attempt:
result = list()
for (i in 1:ncol(mm)) result[[i]] = mm[, i] %*% t(mm[, i])
result[1:2]
# [[1]]
# [,1] [,2] [,3] [,4]
# [1,] 0.9544547 0.3653018 0.7439585 0.8035430
# [2,] 0.3653018 0.1398132 0.2847378 0.3075428
# [3,] 0.7439585 0.2847378 0.5798853 0.6263290
# [4,] 0.8035430 0.3075428 0.6263290 0.6764924
#
# [[2]]
# [,1] [,2] [,3] [,4]
# [1,] 0.3289532 0.3965557 0.2231443 0.2689613
# [2,] 0.3965557 0.4780511 0.2690022 0.3242351
# [3,] 0.2231443 0.2690022 0.1513691 0.1824490
# [4,] 0.2689613 0.3242351 0.1824490 0.2199103
As to why yours didn't work, we can experiment and see that indeed we get a number rather than a matrix. The reason is that when you subset a single row or column of a matrix, the dimensions are "dropped" and it is coerced to a plain vector. And when you matrix multiply two vectors, you get their dot product.
mmt = t(mm)
mm[, 1] %*% mmt[1, ]
# [,1]
# [1,] 2.350646
dim(mm[, 1])
# NULL
dim(mmt[1, ])
# NULL
We can avoid this by specifying drop = FALSE in the subset code
dim(mmt[1, , drop = FALSE])
# [1] 1 4
And thus slightly modify your attempt, just adding drop = FALSE will make it work.
res2 = list()
for (i in 1:ncol(mm)) res2[[i]] = mm[, i] %*% mmt[i, , drop = FALSE]
identical(result, res2)
# [1] TRUE

How do I adjust my function to multiply multiple (random number of) matrices?

I have written the following function for multiplying two matrices A and B:
f <- function(A,B){
m<-nrow(A)
n<-ncol(A)
n<-nrow(B)
p<-ncol(B)
Result<-matrix(0,nrow = m,ncol = p)
for(i in 1:m){
for(j in 1:p){
for(k in 1:n){
Result[i,j]<-Result[i,j]+A[i,k]*B[k,j]
}
}
}
return(Result)
}
How would I adjust my function code to multiple 3 or more, i.e., a random number of matrices rather than just 2?
You just iteratively apply two-matrix multiplication. Let f be the fundamental function multiplying two matrices A and B. Normally we use the internal one %*%, but you can use the one defined in your question.
Since the number of matrices are unknown, I suggest using .... We collect all matrices input into a "matrix list" by list(...), then use Reduce to cumulatively apply two-operand matrix multiplication.
g <- function (...) Reduce(f, list(...))
Note, it is your responsibility to ensure the matrix dimension are conformable, especially when you have a lot of matrices. In the following, I would just use square matrices as an example.
set.seed(0)
A <- matrix(rnorm(4),2)
B <- matrix(rnorm(4),2)
C <- matrix(rnorm(4),2)
f <- "%*%"
g(A, B, C)
# [,1] [,2]
#[1,] -3.753667 0.08634328
#[2,] -0.161250 -1.54194176
And this is as same as:
A %*% B %*% C
# [,1] [,2]
#[1,] -3.753667 0.08634328
#[2,] -0.161250 -1.54194176

Learning R - What is this Function Doing?

I am learning R and reading the book Guide to programming algorithms in r.
The book give an example function:
# MATRIX-VECTOR MULTIPLICATION
matvecmult = function(A,x){
m = nrow(A)
n = ncol(A)
y = matrix(0,nrow=m)
for (i in 1:m){
sumvalue = 0
for (j in 1:n){
sumvalue = sumvalue + A[i,j]*x[j]
}
y[i] = sumvalue
}
return(y)
}
How do I call this function in the R console? And what exactly is passing into this function A, X?
The function takes an argument A, which should be a matrix, and x, which should be a numeric vector of same length as values per row in A.
If
A <- matrix(c(1,2,3,4,5,6), nrow = 2, ncol = 3)
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
then you have 3 values (number of columns, ncol) per row, thus x needs to be something like
x <- c(4,5,6)
The function itself iterates all rows, and in each row, each value is multiplied with a value from x, where the value in the first column is multiplied with the first value in x, the value in As second column is multiplied with the second value in x and so on. This is repeated for each row, and the sum for each row is returned by the function.
matvecmult(A, x)
[,1]
[1,] 49 # 1*4 + 3*5 + 5*6
[2,] 64 # 2*4 + 4*5 + 6*6
To run this function, you first have to compile (source) it and then consecutively run these three code lines:
A <- matrix(c(1,2,3,4,5,6), nrow = 2, ncol = 3)
x <- c(4,5,6)
matvecmult(A, x)
This function is designed to return the product of a matrix A with a vector x; i.e. the result will be the matrix product A x (where - as is usual in R, the vector is a column vector). An example should make things clear.
# define a matrix
mymatrix <- matrix(sample(12), nrow <- 4)
# see what the matrix looks like
mymatrix
# [,1] [,2] [,3]
# [1,] 2 10 9
# [2,] 3 1 12
# [3,] 11 7 5
# [4,] 8 4 6
# define a vector where multiplication of our matrix times the vector will be defined
vec3 <- c(-1,0,1)
# apply the function to our matrix and vector
result <- matvecmult(mymatrix, vec3)
result
# [,1]
# [1,] 7
# [2,] 9
# [3,] -6
# [4,] -2
class(result)
# [1] "matrix"
So matvecmult(mymatrix, vec3) is how you would call this function, and the result is an n by 1 matrix, where n is the number of rows in the matrix argument.
You can also get some insight by playing around and seeing what happens when you pass something other than a matrix-vector pair where the product is defined. In some cases, you will get an error; sometimes you get nonsense; and sometimes you get something you might not expect just from the function name. See what happens when you call matvecmult(mymatrix, mymatrix).
The function is calculating the product of a Matrix and a column vector. It assumes both the number of columns of the matrix is equal to the number of elements in the vector.
It stores the number of columns of A in n and number of rows in m.
It then initializes a matrix of mrows with all values as 0.
It iterates along the rows of A and multiplies each value in each row with the values in x.
The answer is the stored in y and finally it returns the single column matrix y.

Efficient way to calculate array multiplication

Is there any efficient way to calculate 2x2 matrix H without for statement?
n=10
a=array(rnorm(n),c(2,1,n))
b=array(rnorm(n),c(2,1,n))
H=matrix(0,2,2)
for(i in 1:n) H=H+a[,,i] %*% t(b[,,i])
H=matrix(0,2,2)
for(i in 1:n) H=H+a[,,i] %*% t(b[,,i])
H
#----------
[,1] [,2]
[1,] 10.770929 -0.4245556
[2,] -5.613436 -1.7588095
H2 <-a[ ,1, ] %*% t(b[ ,1, ])
H2
#-------------
[,1] [,2]
[1,] 10.770929 -0.4245556
[2,] -5.613436 -1.7588095
This does depend on the arrays in question having one of their dimensions == 1, and on the fact that "[" will drop length-1 dimensions unless you specify drop=FALSE.
This is the same (up to FAQ 7.31 issues) as what you calculate:
In case the second dimension truly has only 1 level, you can use
tcrossprod( matrix(a,nr=2), matrix(b,nr=2) )
and more generally,
crossprod( matrix( aperm(a, c(3,1,2)), nc=2), matrix( aperm(b, c(3,1,2)), nc=2) )
If you can create 'a' and 'b' ordered so that you do not need the aperm() it will be still faster.
The relative speed of different solutions depends on the dimensions. If the first two are both big and the last one small, a loop like yours (but using crossprod) might be as quick as you can get.

How can I make processing of matrices and vectors regular (as, e.g., in Matlab)

Suppose I have a function that takes an argument x of dimension 1 or 2. I'd like to do something like
x[1, i]
regardless of whether I got a vector or a matrix (or a table of one variable, or two).
For example:
x = 1:5
x[1,2] # this won't work...
Of course I can check to see which class was given as an argument, or force the argument to be a matrix, but I'd rather not do that. In Matlab, for example, vectors are matrices with all but one dimension of size 1 (and can be treated as either row or column, etc.). This makes code nice and regular.
Also, does anyone have an idea why in R vectors (or in general one dimensional objects) aren't special cases of matrices (or multidimensional objects)?
Thanks
In R, it is the other way round; matrices are vectors. The matrix-like behaviour comes from some extra attributes on top of the atomic vector part of the object.
To get the behaviour you want, you'd need to make the vector be a matrix, by setting dimensions on the vector using dim() or explicit coercion.
> vm <- 1:5
> dim(vm) <- c(1,5)
> vm
[,1] [,2] [,3] [,4] [,5]
[1,] 1 2 3 4 5
> class(vm)
[1] "matrix"
Next you'll need to maintain the dimensions when subsetting; by default R will drop empty dimensions, which in the case of vm above is the row dimension. You do that using drop = FALSE in the call to '['(). The behaviour by default is drop = TRUE:
> vm[, 2:4]
[1] 2 3 4
> vm[, 2:4, drop = FALSE]
[,1] [,2] [,3]
[1,] 2 3 4
You could add a class to your matrices and write methods for [ for that class where the argument drop is set to FALSE by default
class(vm) <- c("foo", class(vm))
`[.foo` <- function(x, i, j, ..., drop = FALSE) {
clx <- class(x)
class(x) <- clx[clx != "foo"]
x[i, j, ..., drop = drop]
}
which in use gives:
> vm[, 2:4]
[,1] [,2] [,3]
[1,] 2 3 4
i.e. maintains the empty dimension.
Making this fool-proof and pervasive will require a lot more effort but the above will get you started.

Resources