0
votes

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.

2

2 Answers

0
votes

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.

0
votes

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