vectorization - R - Vectorized implementation of ternary function -
i have 3 vectors x
, y
, z
of equal length n
. need create n x n x n
array of function f(x[i],y[j],z[k])
. straightforward way sequentially loop through each element of each of 3 vectors. however, time required compute array grows exponentially n
. there way implement using vectorized operations?
edit: mentioned in comments, have added simple example of what's needed.
set.seed(1) x = rnorm(10) y = seq(11,20) z = seq(21,30) f = array(0, dim=c( length(x),length(y),length(z) ) ) (i in 1:length(x)) (j in 1:length(y)) (k in 1:length(z)) f[i,j,k] = x[i] * (y[j] + z[k])
thanks.
you can use nested outer
:
set.seed(1) x = rnorm(10) y = seq(11,20) z = seq(21,30) f = array(0, dim = c( length(x),length(y),length(z) ) ) (i in 1:length(x)) (j in 1:length(y)) (k in 1:length(z)) f[i,j,k] = x[i] * (y[j] + z[k]) f2 <- outer(x, outer(y, z, "+"), "*") > identical(f, f2) [1] true
a microbenchmark including expand.grid
solution proposed nick k :
x = rnorm(100) y = seq(1:100) z = seq(101:200) forloop <- function(x, y, z) { f = array(0, dim = c( length(x),length(y),length(z) ) ) (i in 1:length(x)) (j in 1:length(y)) (k in 1:length(z)) f[i,j,k] = x[i] * (y[j] + z[k]) return(f) } nestedouter <- function(x, y, z) { outer(x, outer(y, z, "+"), "*") } expandgrid <- function(x, y, z) { df <- expand.grid(x = x, y = y, z = z) g <- df$x * (df$y + df$z) dim(g) <- c(length(x), length(y), length(z)) return(g) } library(microbenchmark) mbm <- microbenchmark( forloop = f1 <- forloop(x, y, z), nestedouter = f2 <- nestedouter(x, y, z), expandgrid = f3 <- expandgrid(x, y, z), times = 50l) > mbm unit: milliseconds expr min lq mean median uq max neval forloop 3261.872552 3339.37383 3458.812265 3388.721159 3524.651971 4074.40422 50 nestedouter 3.293461 3.36810 9.874336 3.541637 5.126789 54.24087 50 expandgrid 53.907789 57.15647 85.612048 88.286431 103.516819 235.45443 50
Comments
Post a Comment