2
votes

lets say I have a tibble which looks like this:

library(tidyverse)
tib <- tibble (a = 1:3, b = 4:6, d = -1:1)

I want to add a column to this tibble where each entry is a function with parameters a,b and d (like f(x) = ax^2 + bx +d). This would mean that (e.g) in the first row I would like to add the function f(x) = 1 x ^2 + 4 x -1, and so on.

I tried the following:

tib2 <- tib %>%
   mutate(fun = list(function(x) {a*x^2+b*x+d}))

This does not work since the functions do not know what a, b and d are.

I managed to build a work-around solution using the function mapply

lf <- mapply(function(a,b,d){return(function(x){a*x^2 + b*x + d})}, tib$a, tib$b, tib$d)
tib3 <- tib %>% 
  add_column(lf)

I was wondering if anyone knows a more elegant way of doing this within the tidyverse. It feels like there is a way using the map function from the purrr package, but I did not manage to get it working.

Thank you

1
what is x? in tib %>% mutate(fun = list(function(x) {a*x^2+b*x+d})) you're passing the whole tibble as an argument, so you expect tibble$a to be multiplied by tibble-squared, etc?lebatsnok
so what I want is that fun is a column which contains functions. x is simply the argument of these functions. So if everything would work fine (which it does in tib3) then select(tib2, fun)[[1]][[1]](1) should return a*1^2+b*1+d, where in this case a,b and d are 1,4 and -1.Cettt
in general, you can easily write such a function as fun <- function(x, df=tib) with(df, a*x^2 + b*x + d) ... so fun(1) will return 4 7 10 etc. Is the idea of attaching a function like this to the tibble? So that would calculate the result each time, istead of storing the result in a static column?lebatsnok
you can store functions in a data frame (perhaps in a tibble too, I've never intentionally used tibbles for anything serious, so I wouldn't really know) but making this useful can be tricky.lebatsnok
thanks for that input. The reason why I want to store the function in the tibble and not its output, is that I need the output for a lot of input variables so it seemed unwise to store them all. Your solution seems to work very well for my needs as well :)Cettt

1 Answers

1
votes

When you used mutate in your example, you were giving it a list with one element (function). So this one function was recycled for all the other rows. Also, inside the definition of the function, it doesn't have any visibility of a, b or d.

You can instead use pmap so that each row has its own function.

tib2 <- tib %>%
  mutate(
    fun = pmap(
      list(a, b, d),
      ~function(x) ..1 * x^2 + ..2 * x + ..3))

tib2
#> # A tibble: 3 x 4
#>       a     b     d    fun
#>   <int> <int> <int> <list>
#> 1     1     4    -1  <fun>
#> 2     2     5     0  <fun>
#> 3     3     6     1  <fun>

tib2$fun[[1]](1)
#> [1] 4