dplyr mutate ifelse returning first value of group instead of by-row

Viewed 293

I'm trying to mutate a data.frame using ifelse:

df = data.frame(grp = c('a', 'a', 'a', 'b', 'b', 'b'), 
                value1 = c(0, 0, 0, 0, 1, 2), 
                value2 = 1:6)


df %>% 
  group_by(grp) %>%
  mutate(value2 = ifelse(all(value1 == 0), 0, value2))

which returns

# # A tibble: 6 x 3
# # Groups:   grp [2]
#  grp   value1 value2
# <chr>  <dbl>  <dbl>
# 1 a          0      0
# 2 a          0      0
# 3 a          0      0
# 4 b          0      4
# 5 b          1      4
# 6 b          2      4

instead of

# # A tibble: 6 x 3
# # Groups:   grp [2]
#  grp   value1 value2
# <chr>  <dbl>  <dbl>
# 1 a          0      0
# 2 a          0      0
# 3 a          0      0
# 4 b          0      4
# 5 b          1      5
# 6 b          2      6

How can I change the mutate so that the rows of "value2" are unchanged if the condition is false?

2 Answers

You can use if and else instead of ifelse():

df %>% 
 group_by(grp) %>%
 mutate(value2 = if(all(value1 == 0)) 0 else value2)

  grp   value1 value2
  <fct>  <dbl>  <dbl>
1 a          0      0
2 a          0      0
3 a          0      0
4 b          0      4
5 b          1      5
6 b          2      6

You can try ifelse as a mask, e.g.,

df %>% 
  group_by(grp) %>%
  mutate(value2 = ifelse(all(value1 == 0), 0, 1)*value2)

or (thank @tmfmnk's comment)

df %>%   
  group_by(grp) %>%  
  mutate(value2 = any(value1 != 0)*value2)

which gives

  grp   value1 value2
  <chr>  <dbl>  <dbl>
1 a          0      0
2 a          0      0
3 a          0      0
4 b          0      4
5 b          1      5
6 b          2      6

The problem you encountered is due to the fact that all(value1 == 0) returns a single logical value. You need to have a vector of logic values to have your desired output, e.g.,

df %>% 
  group_by(grp) %>%
  mutate(value2 = ifelse(rep(all(value1 == 0),n()), 0, value2))
Related