How to define several variables with a foot?

I want to apply a function with several variables with different values ​​to a list. I know how to do this with a single variable.

sapply(c(1:10), function(x) x * 2)
# [1]  2  4  6  8 10 12 14 16 18 20

but not with two. I first show you what I want (actually I use lapply(), but sapply()more synoptic in SO):

# manual
a <- sapply(c(1:10), function(x, y=2) x * y)
b <- sapply(c(1:10), function(x, y=3) x * y)
c <- sapply(c(1:10), function(x, y=4) x * y)
c(a, b, c)
# [1]  2  4  6  8 10 12 14 16 18 20  3  6  9 12 15 18 21 24 27 30  4  8 12 
# [24]  16 20 24 28 32 36 40

And this is my attempt when I try to determine both x, and so y.

# attempt
X <- list(x = 1:10, y = 2:4)
sapply(c(1:10, 2:4), function(x, y) x * y)
# Error in FUN(X[[i]], ...) : argument "y" is missing, with no default

Decision Point

library(microbenchmark)
microbenchmark(sapply = as.vector(sapply(1:10, function(x, y) x * y, 2:4)), 
               mapply = mapply( FUN = function(x, y) x * y, 1:10, rep( x = 2:4, each = 10)),
               sapply2 = as.vector(sapply(1:10, function(y) sapply(2:4, function(x) x * y))),
               outer = c(outer(1:10, 2:4, function(x, y) x * y)))
# Unit: microseconds
# expr        min       lq      mean   median       uq      max neval
# sapply   34.212  36.3500  62.44864  39.1295  41.9090 2304.542   100
# mapply   62.008  65.8570  87.82891  70.3470  76.5480 1283.342   100
# sapply2 196.714 203.9835 262.09990 223.6550 232.2080 3344.129   100
# outer     7.698  10.4775  13.02223  12.4020  13.4715   53.883   100
+6
source share
4 answers

Common decision

Try outer:

c(outer(1:10, 2:4, Vectorize(function(x, y) x*y)))
##  [1]  2  4  6  8 10 12 14 16 18 20  3  6  9 12 15 18 21 24 27 30  4  8 12 16 20
## [26] 24 28 32 36 40

If the function is already vectorized

If the function is already vectorized, as it is here, then we can omit Vectorize:

c(outer(1:10, 2:4, function(x, y) x * y))
##  [1]  2  4  6  8 10 12 14 16 18 20  3  6  9 12 15 18 21 24 27 30  4  8 12 16 20
## [26] 24 28 32 36 40

, , :

c(outer(1:10, 2:4))
##  [1]  2  4  6  8 10 12 14 16 18 20  3  6  9 12 15 18 21 24 27 30  4  8 12 16 20
## [26] 24 28 32 36 40

:

c(1:10 %o% 2:4)
##  [1]  2  4  6  8 10 12 14 16 18 20  3  6  9 12 15 18 21 24 27 30  4  8 12 16 20
## [26] 24 28 32 36 40

X

- X, , :

c(outer(X[[1]], X[[2]], Vectorize(function(x, y) x * y)))
##  [1]  2  4  6  8 10 12 14 16 18 20  3  6  9 12 15 18 21 24 27 30  4  8 12 16 20
## [26] 24 28 32 36 40

c(do.call("outer", c(unname(X), Vectorize(function(x, y) x*y))))
##  [1]  2  4  6  8 10 12 14 16 18 20  3  6  9 12 15 18 21 24 27 30  4  8 12 16 20
## [26] 24 28 32 36 40

, , .

+5

mapply()

mapply() .

rep() 2, 3 4. 10 each, rep() x 10 .

, mapply() - 1:10 - 10.

# supply the function first, followed by the
# arguments in the order in which they are called in `FUN`
mapply( FUN = function(x, y) x * y
        , 1:10
        , rep( x = 2:4, each = 10)
)

# [1]   2  4  6  8 10 12 14 16 18 20  3  6  9 12 15 18 21 24 27 30  4  8 12 16 20
# [26] 24 28 32 36 40
+6

, lapply(), . :

x <- 1:10
unlist(lapply(2:4, function(y) x*y))
# OR
unlist(lapply(2:4, function(x=x,y) x*y))

-, , outer():

xf <- 1:10
yf <- 2:4
c(xf %o% yf)
# OR spelled out for any function:
c(outer(xf,yf,FUN = `*`))

mapply, MoreArgs, rep :

xf <- 1:10
yf <- 2:4
mapply(function(x,y) x*y,
       y = yf,
       MoreArgs = list(x = xf))

lapply(), . SIMPLIFY = FALSE unlist():

unlist(mapply(function(x,y) x*y,
              y = yf,
              MoreArgs = list(x = xf),
              SIMPLIFY = FALSE))

, . , R, , outer() , .

, , ( ). , :

  • outer() , .
  • mapply() , sapply() .

: :

fx <- sample(1e4)
fy <- sample(1e3)
library(microbenchmark)
microbenchmark(sapply = as.vector(sapply(fx, function(x, y) x * y, fy)), 
               mapply = mapply( FUN = function(x, y) x * y, fx, rep( fy, each = 1e4)),
               sapply2 = as.vector(sapply(fx, function(y) sapply(fy, function(x) x * y))),
               outer = c(outer(fx, fy, function(x, y) x * y)),
               mapply2 = mapply(function(x,y) x*y, x=fx, MoreArgs = list(y = fy)),
               mapply3 = mapply(function(x,y) x*y, y=fy, MoreArgs = list(x = fx)),
               times = 15)

:

Unit: milliseconds
    expr         min          lq       mean      median          uq        max neval cld
  sapply    89.52318    92.98653   344.1538   117.11280   239.64887  1485.3178    15 a  
  mapply 20471.02137 22925.42757 24478.5985 24650.29055 25627.31232 28840.3494    15   c
 sapply2  7472.02251  8268.04696  9519.8016  8707.19193  9528.46181 14182.7537    15  b 
   outer    77.62331    85.94651   189.5107    91.83722   182.08506  1119.6620    15 a  
 mapply2    77.76871    79.71924   143.9484    81.24168    84.53247   971.1792    15 a  
 mapply3    65.21709    71.85662   107.9586    73.80779   124.21141   242.0760    15 a  
+5

- sapply.

as.vector(sapply(2:4, function(y) sapply(1:10, function(x) x * y)))
[1]  2  4  6  8 10 12 14 16 18 20  3  6  9 12 15 18 21 24 27 30  4  8 12 16 20 24 28 32 36 40

Or we can use map2_intfrom the package purrr. map2_intcan go through two vectors with the same length and make sure that the output is integer. Therefore, we must use rep(a, length(b))and rep(b, each = length(a))to make sure that each element is conjugated. ~.x * .yis a short way to set function c purrr.

library(purrr)

a <- 1:10
b <- 2:4
map2_int(rep(a, length(b)), rep(b, each = length(a)), ~.x * .y)
# [1]  2  4  6  8 10 12 14 16 18 20  3  6  9 12 15 18 21 24 27 30  4  8 12 16 20 24 28 32 36 40
+3
source

All Articles