r: %*% and lapply/mapply when arguments are reversed - r

I have been wondering the most efficient way to do matrix multiplication on lists.
Let's say I have a matrix A and a list of matrices B:
A = matrix(c(1,2,3,4), ncol=2, nrow=2)
B = list(matrix(c(1,2,3,4), ncol=2, nrow=2), matrix(c(4,3,2,1), ncol=2, nrow=2))
And I want the list of crossproducts of A and each element b of B:
A %*% b
I was trying to use lapply() but couldn't figure out how to ensure the right sequence of multiplication without extra nested lapply's to transpose each b...
lapply(B, '%*%', A) # which gives a list of b%*%A rather than A%*%b
lapply(lapply(lapply(B, t), '%*%', t(A)), t) # gives the answer but geez...
Could anyone kindly give me some pointers here?

Just define your function inside lapply(), like so
lapply(B, function(x) A%*%x)

Related

Non-conformable arguments when using apply

I have a 10000 x 7 data.table dat . I would like to multiply each row of dat by a 7x7 matrix c. I have tried the following
apply(dat, 1, function(x) sqrt(as.matrix(x) %*% as.matrix(c) %*% t(as.matrix(x))))
I get this error
Error in as.matrix(x) %*% as.matrix(c) : non-conformable arguments
This function works when I take a single row from dat (so 1 x 7) but not when I use apply.
How do I make this work using apply?
Thanks!
Additional info - I could achieve what I need another way. I could multiply the entire data.frame by the matrix and take sqrt(diag(x)). However, I need to do this a lot of times, so it would be more efficient to take this row by row and return a single figure.
I think you should use t(as.matrix(x))%*% as.matrix(c) %*% as.matrix(x) in your apply function, since the argument as.matrix(x) is indeed a column-vector (not a row-vector).
res <- apply(dat, 1, function(x) sqrt(t(as.matrix(x))%*% as.matrix(c) %*% as.matrix(x)))
Example
set.seed(1)
dat <- data.frame(matrix(sample(70),ncol = 7))
c <- matrix(sample(49),ncol = 7)
res <- apply(dat, 1, function(x) sqrt(t(as.matrix(x))%*% as.matrix(c) %*% as.matrix(x)))
such that
> res
[1] 1522.7206 1208.6306 1105.7509 1063.4341 1066.3423 1124.8271
[7] 1219.2280 1665.8301 1609.4704 954.3694
Note: c() is a commonly used function in R, using c as variable name is therefore not good practice, I use c_ below instead.
When multiplying matrices the number of columns in the first matrix needs to be the same as the number of rows in the second. In the as.matrix(x) %*% as.matrix(c) part in your code the first matrix has one column and the second has 7 rows. That is why you get the error.
Multiplying the transposed row of dat with c first and then the row fixes this.
apply(dat2, 1, function(x) sqrt(t(as.matrix(x)) %*% as.matrix(c_) %*% (as.matrix(x))))
Or making the function more explicit in regard to the matrix you want to create from the row also works:
apply(dat, 1, function(x) sqrt(matrix(x, 1) %*% c_ %*% t(matrix(x, 1))))
Both solutions produce the same results.

list with matrices times always the same vector

i am working with consumer price index CPI and in order to calculate it i have to multiply the index matrix with the corresponding weights:
grossCPI77_10 <- grossIND1977 %*% weights1910/100
grossCPI82_10 <- grossIND1982 %*% weights1910/100
of course i would rather like to have a code like the one beyond:
grossIND1982 <- replicate(20, cbind(1:61))
grossIND1993 <- replicate(20, cbind(1:61))
weights1910_sc <- c(1:20)
grossIND_list <- mget(ls(pattern = "grossIND...."))
totalCPI <- mapply("*", grossIND_list, weights1910_sc)
the problem is that it gives me a 1200x20 matrix. i expected a normal matrix (61x20) vector (20x1) multiplication which should result in a 20x1 vector? could you explain me what i am doing wrong? thanks
part of your problem is that you don't have matrices but 3D arrays, with one singleton dimension. The other issue is that mapply likes to try and combine the results into a matrix, and also that constant arguments should be passed via MoreArgs. But actually, this is more a case for lapply.
grossIND1982 <- replicate(20, cbind(1:61))[,1,]
grossIND1993 <- replicate(20, cbind(1:61))[,1,]
weights1910_sc <- c(1:20)
grossIND_list <- mget(ls(pattern = "grossIND...."))
totalCPI <- mapply("*", grossIND_list, MoreArgs=list(e2 = weights1910_sc), SIMPLIFY = FALSE)
totalCPI <- lapply(grossIND_list, "*", e2 = weights1910_sc)
I am not sure if I understood all aspects of your problem (especially concerning what should be colums, what should be rows, and in which order the crossproduct shall be applied), but I will try at least to cover some aspects. See comments in below code for clarifications of what you did and what you might want. I hope it helps, let me know if this is what you need.
#instead of using mget, I recommend to use a list structure
#otherwise you might capture other variables with similar names
#that you do not want
INDlist <- sapply(c("1990", "1991"), function(x) {
#this is how to set up a matrix correctly, check `?matrix`
#I think your combination of cbind and rep did not give you what you wanted
matrix(rep(1:61, 20), nrow = 61)
}, USE.NAMES = TRUE, simplify = F)
weights <- list(c(1:20))
#the first argument of mapply needs to be a function, in this case of two variables
#the body of the function calculates the cross product
#you feed the arguments (both lists) in the following part of mapply
#I have repeated your weights, but you might assign different weights for each year
res <- mapply(function(x, y) {x %*% y}, INDlist, rep(weights, length(INDlist)))
dim(res)
#[1] 61 2

Given a list of n 4x4 matrices, how do I combine them such that they follow consecutively resulting in a 4nx4 matrix

What I want to do is given a list [mat1, mat2, mat3, ..., matn] where each matrix is 4x4 create a large 4nx4 matrix:
mat1
mat2
mat3
I did this using a loop but my list is about 12000 matrices and it took forever... how could I do this in a more efficient way?
do.call(rbind, list(mat1, mat2, mat3))
or
## Collect the matrices into a list
MATS <- lapply(paste0("mat", 1:n), function(x) get(x))
## rbind them all into one
do.call(rbind, MATS)
The abind package is useful for this kind of thing as it will directly accept a list. It's definitely worth knowing about for manipulating matrices and arrays.
library(abind)
mat <- matrix(1, ncol = 4, nrow = 4)
abind(list(mat, mat), along = 1)

Create matrix with elements returned by a function

I have two vectors x and y with some values and I need to generate the matrix which elements would be returned by a function f(x,y) applied to those 2 vectors. That is the matrix M will have a typical element
M[i,j] <- f(x[i], y[j])
What is the most efficent way to do this if I want to avoid loops? I can generate matrix columns or rows by using sapply function, i.e.
M[i, ] <- sapply(y, f, x = x[i])
But I still need to apply loop in other dimension which is very slow, because the dimension of x is huge. Is it possible to use apply family of function and avoid loops completely?
That is exactly what the outer function does:
outer(x, y, f)
If f is not vectorized, you need:
outer(x, y, Vectorize(f))

Force apply to return a list

I have a matrix and a function that takes a vector and returns a matrix. I want to apply the function to all rows of the matrix and rbind all results together. For example
mat <- matrix(1:6, ncol=2)
f <- function (x) cbind(1:sum(x), sum(x):1)
do.call(rbind, apply(mat, 1, f))
This works perfectly since the returned matrices have different numbers of rows so apply returns a list. But if they happen to have the same numbers of rows this does not work anymore:
mat <- f(3)
apply(mat, 1, f)
apply returns a matrix from which I cannot get the result I want. Is it possible to force apply to return a list or is there another solution?
This is why I love the plyr package. It has a number of --ply functions that all work in the same way. The first letter corresponds to what you have as input and the second method corresponds to what you have as output (l for lists, a for arrays, d for data frames).
So the alply() function works similar to apply() but always returns a list:
alply(mat, 1, f)
You have to split matrix mat before applying function f.
list_result <- lapply(split(mat,seq(NROW(mat))),f)
matrix_result <- do.call(rbind,list_result)

Resources