dplyr mutate not applying to individual element of field
dplyr mutate not applying to individual element of field
I'm trying to do a calculation using an home made function inside a mutate
call and it's not doing what I'm expecting it to do.
mutate
Here is a reproducible example:
library(dplyr)
#the data
dd <- structure(list(fire_zone = c("ET", "EJB", "WJB"), base_med = c(1, 1, 2)), class = "data.frame", row.names = c(NA, -3L))
# my home made function
med2lambda <- function(med) polyroot(c(-0.02, 1/3 - med, 1)) %>% suppressWarnings(as.numeric(.)) %>% max
So, what my function does is to estimate the lambda associated to the median from a Poisson distribution by calculating the root of a quadratic function. Despite the long explanation, it's actually pretty basic:
med2lambda(1)
[1] 0.695426
med2lambda(2)
[1] 1.678581
Now, I want to use it in a mutate
call to add a field giving the lambda associated to each median in the table:
mutate
dd %>% mutate(lambda = med2lambda(base_med), log = log(base_med))
fire_zone base_med lambda log
1 ET 1 2.128966 0.0000000
2 EJB 1 2.128966 0.0000000
3 WJB 2 2.128966 0.6931472
The result is wrong, mutate actually gives me the results of:
med2lambda(dd$base_med)
[1] 2.128966
I've added the log
call in the mutate
to give an idea of what it should do. log
works great in the mutate
as it is called element by element.
log
mutate
log
mutate
Any insight about this behavior would be appreciated.
group_by(base_med) %>%
mutate
not really, I don't want the ones to be grouped togethere, I really just want my function to work the same way as the
log
function for example– Bastien
Sep 14 '18 at 16:59
log
@Bastien
log
is vectorised, your function med2lambda
is not. Please see my answer below.– Maurits Evers
Sep 14 '18 at 17:02
log
med2lambda
2 Answers
2
You need to allow med2lambda
to take vectors instead of scalars.
med2lambda
One possibility is to use Vectorize
:
Vectorize
med2lambda.vectorised <- Vectorize(med2lambda)
dd %>% mutate(lambda = med2lambda.vectorised(base_med), log = log(base_med))
# fire_zone base_med lambda log
#1 ET 1 0.695426 0.0000000
#2 EJB 1 0.695426 0.0000000
#3 WJB 2 1.678581 0.6931472
Alternatively, you could rewrite med2lambda
to take a vector as argument:
med2lambda
med2lambda2 <- function(med) sapply(med, function(x)
polyroot(c(-0.02, 1/3 - x, 1)) %>% suppressWarnings(as.numeric(.)) %>% max)
dd %>% mutate(lambda = med2lambda2(base_med), log = log(base_med))
# fire_zone base_med lambda log
#1 ET 1 0.695426 0.0000000
#2 EJB 1 0.695426 0.0000000
#3 WJB 2 1.678581 0.6931472
Thanks, I didn't know about
Vectorize
. Seems to to exactly what I need. Also, how would I rewrite med2lambda
to take vector as argument, I'm not quite sure I know how to do that?– Bastien
Sep 14 '18 at 17:15
Vectorize
med2lambda
@Bastien You could use
sapply
inside med2lamba2
; I've updated my answer to demonstrate. Please take a look.– Maurits Evers
Sep 14 '18 at 17:33
sapply
med2lamba2
We can use map
map
library(tidyverse)
dd %>%
mutate(lambda = map_dbl(base_med, med2lambda), log = log(base_med))
Thanks for contributing an answer to Stack Overflow!
But avoid …
To learn more, see our tips on writing great answers.
Required, but never shown
Required, but never shown
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
If I'm interpreting your question correctly, I think you need to add
group_by(base_med) %>%
before yourmutate
call.– JasonAizkalns
Sep 14 '18 at 16:56