有效地将3维数组中的不同矩阵与R中的不同向量相乘

时间:2019-04-17 21:41:09

标签: r vectorization matrix-multiplication tensor mapply

我有Z,这是一个n=1000 x m=500,000 x p=3数组,Y,是一个p=3 x n=1000矩阵。 对于i中的每个1:n,我想矩阵乘法: Z[i, ,] %*% Y[, i]

我觉得应该有一个更快的方法来做到这一点,可能涉及到张量,或者仅仅是更好的矢量化。

我对矩阵Y有一种特殊形式,如下文mwe中所述。我对利用这种结构的解决方案以及没有利用这种结构的更通用的解决方案感兴趣。

内存也是一个问题,因为您似乎至少需要将Z对象的大小增加一倍。我设定m = 10,000使生活更轻松,但实际上m = 500,000。

n=1000; m=10000; p=3
Z = array( rnorm(n*m*p) , dim = c(n, m, p))
Y = matrix(NA, nrow=p, ncol = n)
index = rbinom(n,1,0.5)==1
Y[,index] = c(0,1,2)
Y[,!index] = c(2,1,0)
pryr::object_size(Z)
pryr::object_size(Y)

# methods that do not rely on the structure of Y
method1 = do.call(cbind,matrix(mapply(plyr::alply(.data = Z, .margins = 1), plyr::alply(Y, .margins = 2), FUN = function(x,y) x %*% y , SIMPLIFY = FALSE )))
method2 = do.call(cbind,matrix(map2(.x = plyr::alply(.data = Z, .margins = 1), .y = plyr::alply(Y, .margins = 2 ), ~ .x %*% .y ) ))
method3 =  do.call(cbind,lapply(seq_len(dim(Z)[1]),function(i) Z[i,,]%*%Y[,i]))
identical(method1, method2)
identical(method2, method3)

# method that does rely on the structure of Y
fn4 = function(Z, index){
  m = dim(Z)[2]; n = dim(Z)[1]
  res = matrix(NA, m, n)
  method4.1 = apply( Z[index,,], 1, function(x) x %*% c(0,1,2) )
  method4.2 = apply( Z[!index,,], 1, function(x) x %*% c(2,1,0) )
  res[,index] = method4.1
  res[,!index] = method4.2
  res
}
method4 = fn4(Z, index)
identical(method4, method3)

bench::mark(
  method1 = do.call(cbind,matrix(mapply(plyr::alply(.data = Z, .margins = 1), plyr::alply(Y, .margins = 2), FUN = function(x,y) x %*% y , SIMPLIFY = FALSE ))),
  method2 = do.call(cbind,matrix(map2(.x = plyr::alply(.data = Z, .margins = 1), .y = plyr::alply(Y, .margins = 2 ), ~ .x %*% .y ) )),
  method3 = do.call(cbind,lapply(seq_len(dim(Z)[1]),function(i) Z[i,,]%*%Y[,i])),
  method4 = fn4(Z, index),
  iterations = 4
)

0 个答案:

没有答案
相关问题