Mutate with nested ifesle

Viewed 50

I do get the wrong result, what am I doing wrong?

df <- data.frame(x=c(1,1,NA),y=c(1,NA,NA),z=c(NA,NA,NA))
df <-mutate(df,result=ifelse(is.na(x),NA,ifelse(any(!is.na(y),!is.na(z)),1,0)))

I get this (data[2,4]==0)

   x  y  z result
1  1  1 NA      1
2  1 NA NA      1
3 NA NA NA     NA

Instead of this:

df_wanted <- data.frame(x=c(1,1,NA),y=c(1,NA,NA),z=c(NA,NA,NA), result=c(1,0,NA))

   x  y  z result
1  1  1 NA      1
2  1 NA NA      0
3 NA NA NA     NA

2 Answers

We can use | instead of any because any returns a single TRUE/FALSE as output

with(df, any(!is.na(y), !is.na(z)))
#[1] TRUE

and that gets recycled for the entire column and because the first ifelse with 'x' returns already 'NA' for the third row, all the others are returned 1

instead we need to do this for each row and this can be accomplished with |

library(dplyr)
df %>%
   mutate(result = ifelse(is.na(x), NA, ifelse(!is.na(y)|!is.na(z), 1, 0)))
#   x  y  z result
#1  1  1 NA      1
#2  1 NA NA      0
#3 NA NA NA     NA

Or another option is case_when

df %>%
  mutate(result = case_when(is.na(x) ~ NA_integer_, 
                        !is.na(y)| !is.na(z) ~ 1L, 
                        TRUE ~ 0L))
#   x  y  z result
#1  1  1 NA      1
#2  1 NA NA      0
#3 NA NA NA     NA

Or with coalesce

df %>%
   mutate(result = x * +coalesce(!is.na(y)|!is.na(z)))
#   x  y  z result
#1  1  1 NA      1
#2  1 NA NA      0
#3 NA NA NA     NA

You can use case_when and mention each condition explicitly.

library(dplyr)

df %>%
  mutate(result = case_when(is.na(x) ~ NA_integer_, 
                            !(is.na(y) & is.na(z)) ~ 1L, 
                            TRUE ~ 0L))


#   x  y  z result
#1  1  1 NA      1
#2  1 NA NA      0
#3 NA NA NA     NA
Related