Function equivalent to ifelse in brms package

I wonder if there is a function equivalent to ifelse in the following code in brms package if I have more than 2 groups (five groups).

set.seed(1)
d <-tibble(group = rep(c("normal","cases"), each = n)) %>%
mutate(cases = ifelse(group =="normal",0,1),
y = ifelse(group =="normal",
rnorm(n, mean = mu_n, sd =1),
rnorm(n, mean = mu_c, sd =1)))

@May, could you please tell us more about what you’re trying to do? It looks like you want to simulate data, which is best done with other packages focused on these tasks instead of brms. If simulating data is what you want to do, I suggest looking into dplyr::case_when (html). This function allows you to put together multiple if/ifelse type statements. You’ll need to also use rowwise() to make sure that the random number generator works properly.

library(tidyverse)
set.seed(1)

n <- 50       # number of reps/group
mu_n <- 1  # means for each group
mu_c <- 2
mu_i <- 3
mu_j <- 4
mu_k <- 5

d <- tibble(group = rep(c("normal", "cases", "i", "j", "k"), each = n)) %>%
  rowwise() %>%  # this ensures that random number generator works on each row
  mutate(cases = ifelse(group =="normal", 0, 1),
         y = case_when(
           # logical test to identify which rows to modify ~ value to use when TRUE
           group == "normal" ~ rnorm(n = 1, mean = mu_n, sd = 1),
           group == "cases" ~ rnorm(n = 1, mean = mu_c, sd = 1),
           group == "i" ~ rnorm(n = 1, mean = mu_i, sd = 1),
           group == "j" ~ rnorm(n = 1, mean = mu_j, sd = 1),
           group == "k" ~ rnorm(n = 1, mean = mu_k, sd = 1)
         )) %>%
  ungroup()  # remove rowwise grouping

# plot histogram of 'y' values by 'group' & colored by value of 'cases'
ggplot(d, aes(x = y, fill = cases))+
  geom_histogram()+
  facet_wrap(~group)

That is exactly what I want, when I tried to do it in my model

set.seed(1)

n <- 50       # number of reps/group
mu_n <- 0  # means for each group
mu_c1 <- 0.2
mu_c2 <- 0.3
mu_c3 <- 0.3
mu_c4 <- 0.4

d <- tibble(group = rep(c("normal", "covid1", "covid2", "covid3", "covid4"), each = n)) %>%
  rowwise() %>%  
  mutate(cases = rep(c (0, 1,2,3,4),each=n),
         y = case_when(
           group == "normal" ~ rnorm(n , mean = mu_n, sd = 1),
           group == "covid1" ~ rnorm(n , mean = mu_c1, sd = 1),
           group == "covid2" ~ rnorm(n, mean = mu_c2, sd = 1),
           group == "covid3" ~ rnorm(n, mean = mu_c3, sd = 1),
           group == "covid4" ~ rnorm(n, mean = mu_c4, sd = 1)
         )) %>%
  ungroup() 

I got that error

Error in `$<-.data.frame`(`*tmp*`, "call_text", value = c("... %>% ungroup()", : 
replacement has 6 rows, data has 2

This isn’t a Stan/brms issue—the data manipulation is using other packages in the tidyverse and in the future would be better asked on a different forum (e.g., StackOverflow). I know it’s hard to tell sometimes: at the top of the help page (e.g. type in ?mutate to the R console), the name of the package is in curly braces (e.g., mutate {dplyr}). You’ll get more/better responses on this forum for the R packages listed here: Stan - Interfaces.

But we’re all just trying to learn on this forum, so let’s get your problem fixed anyway…
The error is caused by rowwise(). This treats each row as a group and does the commands that follow for each row until the grouping is changed (e.g., removed with ungroup()). You’re getting errors because the mutate commands are trying to put more than one value per row. (Note: multiple values per row is possible with list columns, but I don’t think that’s what you’re trying to do).

To fix:

  • move the cases = ... line up into tibble. Not the only way to do this, but seems reasonable enough for your example.
  • set n = 1 for all of the rnorm(n = ...)s in each line of case_when. Remember, you’re grouping by row: you’re going to call rnorm(...) individually for each row and only one value can fit (not 50). This isn’t the fastest/most efficient way to do this task, but it will get the job done and is reasonably easy for humans to read and understand.
d <- tibble(group = rep(c("normal", "covid1", "covid2", "covid3", "covid4"), each = n),
            cases = rep(c (0, 1, 2, 3, 4), each = n)) %>%
  rowwise() %>%  
  mutate(y = case_when(
           group == "normal" ~ rnorm(n = 1, mean = mu_n, sd = 1),
           group == "covid1" ~ rnorm(n = 1, mean = mu_c1, sd = 1),
           group == "covid2" ~ rnorm(n = 1, mean = mu_c2, sd = 1),
           group == "covid3" ~ rnorm(n = 1, mean = mu_c3, sd = 1),
           group == "covid4" ~ rnorm(n = 1, mean = mu_c4, sd = 1)
         )) %>%
  ungroup() 
1 Like

You can simplify the code by setting up a data frame of simulation parameters and then generating the simulations as a list column containing the nested values:

library(tidyverse)

# Number of simulations per group
n = 50 

# Simulation groups and parameters
params = tibble(group=c("normal","cases","i","j","k"),
                cases=ifelse(group=="normal",0,1),
                mu=1:5)

set.seed(1)
d = params %>% 
  mutate(sims = map(mu, ~rnorm(n, .x, 1)))

d
#> # A tibble: 5 Ă— 4
#>   group  cases    mu sims      
#>   <chr>  <dbl> <int> <list>    
#> 1 normal     0     1 <dbl [50]>
#> 2 cases      1     2 <dbl [50]>
#> 3 i          1     3 <dbl [50]>
#> 4 j          1     4 <dbl [50]>
#> 5 k          1     5 <dbl [50]>
# Unnest if you want a "long" data frame
d %>% unnest(sims)
#> # A tibble: 250 Ă— 4
#>    group  cases    mu  sims
#>    <chr>  <dbl> <int> <dbl>
#>  1 normal     0     1 0.374
#>  2 normal     0     1 1.18 
#>  3 normal     0     1 0.164
#>  4 normal     0     1 2.60 
#>  5 normal     0     1 1.33 
#>  6 normal     0     1 0.180
#>  7 normal     0     1 1.49 
#>  8 normal     0     1 1.74 
#>  9 normal     0     1 1.58 
#> 10 normal     0     1 0.695
#> # … with 240 more rows

Thank you very much.