How to collect outputs of multivariable vector-valued function into a dataframe?

Viewed 57

I have a function f1 that take a pair of real numbers (x, y) and returns a triple of real numbers. I would like to collect all outputs of this function for all x in a vector a and y in a vector b. Could you please elaborate on how to do so?

f1 <- function(x, y){
  return (c(x+y, x-y, x*y))
}

a <- seq(0, pi, 0.1)
b <- seq(0, 2 * pi, 0.1)

Update: I mean for all pair $(x, y) \in a \times b$.

3 Answers

Here is a data.table option

setDT(expand.grid(a, b))[, fval := do.call(Vectorize(f1, SIMPLIFY = FALSE), unname(.SD))][]

where expand.grid + do.call + Vectorize are used, giving

      Var1 Var2              fval
   1:  0.0  0.0             0,0,0
   2:  0.1  0.0       0.1,0.1,0.0
   3:  0.2  0.0       0.2,0.2,0.0
   4:  0.3  0.0       0.3,0.3,0.0
   5:  0.4  0.0       0.4,0.4,0.0
  ---
2012:  2.7  6.2  8.90,-3.50,16.74
2013:  2.8  6.2  9.00,-3.40,17.36
2014:  2.9  6.2  9.10,-3.30,17.98
2015:  3.0  6.2     9.2,-3.2,18.6
2016:  3.1  6.2  9.30,-3.10,19.22

A more compact one is using CJ(a,b) instead of setDT(expand.grid(a, b)) (Thank @akrun's advise)

We can use expand.grid to expand the data between 'a', and 'b' values, then loop over the row with apply, MARGIN = 1 and apply the f1

out <- as.data.frame(t(apply(expand.grid(a, b), 1, function(x) f1(x[1], x[2]))))

Or with tidyverse

library(dplyr)
library(purrr)
library(tidyr)

out2 <- crossing(x = a, y = b) %>% 
       pmap_dfr(f2)

-output

head(out2)
# A tibble: 6 x 3
#    add subtract multiply
#  <dbl>    <dbl>    <dbl>
#1   0        0          0
#2   0.1     -0.1        0
#3   0.2     -0.2        0
#4   0.3     -0.3        0
#5   0.4     -0.4        0
#6   0.5     -0.5        0

where f2

f2 <- function(x, y){
    return (tibble(add = x+y, subtract = x-y, multiply = x*y))
  }

It may be better to return a list or tibble so that it becomes easier

Create all possible combinations with expand.grid and use Map to apply f1 to every pair.

val <- expand.grid(a, b)
result <- do.call(rbind, Map(f1, val$Var1, val$Var2))
head(result)

#     [,1] [,2] [,3]
#[1,]  0.0  0.0    0
#[2,]  0.1  0.1    0
#[3,]  0.2  0.2    0
#[4,]  0.3  0.3    0
#[5,]  0.4  0.4    0
#[6,]  0.5  0.5    0
Related