2

I have some data, some of which is replicated, some not. I can only fit my model for the replicated data.

library(tidyverse)
d <- tribble(
  ~env, ~val,
  "A",  1,
  "A",  2,
  "B",  3
)

I am using tidyr::nest() and purrr::map() functions to fit my model. However, in every function I use for map() I had to cater for the special case that a particular set of data is not modellable, which i archieved via calls in the style of

map(col, function(elem){ if(!is.null(elem)) DO_STUFF(elem) else NULL})

After a while, I managed to extract this behaviour to a purrr-style adverb function which takes another function and wraps it such that this behaviour for NULL elements is automatic:

maybe <- function(fun){
  function(val,...){ if(!is.null(val)) fun(val, ...) else NULL}
}

However, this left me wondering: Am I duplicating behaviour which is already archievable using tidyverse functions?

Bonus question: Is there a word in functional programming for a function like maybe?


This is an example to test my adverb:

Simple Model: A mean for data in environment A and no model for data in environment B (since the data is unreplicated:)

modelFuns <- list(A = mean, B = NULL)

Group data by environment and determine the appropriate model for each group

d <- d %>% group_by(env) %>% nest(.key = "data")
d %<>% mutate(model = modelFuns[env])
d

## # A tibble: 2 x 3
##   env   data             model 
##   <chr> <list>           <list>
## 1 A     <tibble [2 × 1]> <fn>  
## 2 B     <tibble [1 × 1]> <NULL>

Perform modelling:

d %<>% mutate(out = pmap(list(model, data), maybe(function(m,d) m(d$val))))
d

## # A tibble: 2 x 4
##   env   data             model  out      
##   <chr> <list>           <list> <list>   
## 1 A     <tibble [2 × 1]> <fn>   <dbl [1]>
## 2 B     <tibble [1 × 1]> <NULL> <NULL>

Which is equivalent to the following code which does not use my maybe adverb:

d %<>% mutate(out = pmap(list(model, data), function(m,d){if(!is.null(m)) m(d$val) else NULL}))
d

## # A tibble: 2 x 4
##   env   data             model  out      
##   <chr> <list>           <list> <list>   
## 1 A     <tibble [2 × 1]> <fn>   <dbl [1]>
## 2 B     <tibble [1 × 1]> <NULL> <NULL>

The fact that there might be a value or there might be NULL propagates to everything I want to do with the modelling results downstream, which is why the adverb maybe is useful. Does something like this already exist in the tidyverse?

isModelNice <- function(val) val > 0
d %<>% mutate(nice = map(out, maybe(isModelNice)))
d

## # A tibble: 2 x 5
##   env   data             model  out       nice     
##   <chr> <list>           <list> <list>    <list>   
## 1 A     <tibble [2 × 1]> <fn>   <dbl [1]> <lgl [1]>
## 2 B     <tibble [1 × 1]> <NULL> <NULL>    <NULL>

1 Answer 1

3

could you use purrr::possibly()?

library(tidyverse)

d <- tribble(
  ~env, ~val,
  "A",  1,
  "A",  2,
  "B",  3
)

modelFuns <- list(A = mean, B = NULL)

d %>% group_by(env) %>% 
  nest(.key = "data") %>% 
  mutate(model = modelFuns[env]) %>% 
  mutate(out = pmap(list(model, data), possibly(function(m,d) m(d$val), NULL)))
Sign up to request clarification or add additional context in comments.

1 Comment

OK, this works if my model function throws an error if I give a NULL value. Not exactly the behaviour I looked for (what if my model function returns numeric(0) or whatever given a NULL argument), but might be working for this particular case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.