Let's consider a tibble with repeated arguments like this:
data <- tibble(
~x, ~y,
"A", "17:145:01800",
"B", "17:145:01800",
"C", "17:145:01800",
"A", "17:146:01800",
"B", "17:146:01800",
"C", "17:146:01800",
)
Now I want to create a column z which is the output of a function of y. The "slow" method would be:
data %>% mutate(z=myfunc(y))
However, as the input repeats 3 times in this case (one for each value of x), I consider a grouping approach to avoid calculate the same twice:
# Version 1
data %>%
group_by(y) %>%
nest() %>% # now the tibble has only 2 rows
mutate(z=myfunc(y)) %>%
unnest(c("data"))
# Version 2
data %>%
group_by(y) %>%
mutate(z=myfunc(y))
What should be faster? Version 1 or version 2?
I wonder if grouping would reduce the number of times myfunc is called, or if nesting is necessary for this. I tried to do some testing, but with small number of rows maybe the nesting and unnesting makes results different...I particularly want to apply this to a tibble with a lot of different x's (~350) and different y's (~9600)
Thanks in advance.
Solution
I found a way to improve a lot the performance. First, run the function only on unique values: dict <- myfunc(unique(y)) . Then, name the vector names(dict) <- unique(y). Then you can get the value by looking at the vector for each input data$z <- dict[data$y]. Or use a mutate() alternative to this. I think it is also possible to use a left_join() approach to this but I havent tried. Results of a microbenchmark I tried on it (oldthing is just using data$z <- myfunc(data$y) and newthing is the approach I just described).
Unit: milliseconds
expr min lq mean median uq max neval
nothing 36.434995 57.39253 93.38216 82.91927 109.70960 588.06789 100
group 156.039489 338.40348 457.83076 426.54913 562.26887 1807.16725 100
groupunique 112.453367 248.53734 365.68583 327.62761 442.73981 1494.96353 100
oldthing 34.265350 56.41572 85.71731 73.83113 105.02589 493.63245 100
newthing 5.147881 10.93754 14.69213 12.67236 14.66174 89.80508 100