Reputation: 915
I'm trying to use mutate
and if_else()
to get the result of following logical statement applied to two columns of a data frame:
True if Yes in a or b, NA if NA in both, FALSE if both No or No & NA
library(magrittr)
library(dplyr)
data.frame(
"a"=c(NA,"No","Yes","Yes","No","No",NA),
"b"=c(NA,"No","Yes","No","Yes",NA,"No")
) %>%
mutate(
logical = if_else(
a == "Yes" | b == "Yes",
TRUE,
if_else(
is.na(a) & is.na(b),
NA,
FALSE
)
)
)
#> a b logical
#> 1 <NA> <NA> NA
#> 2 No No FALSE
#> 3 Yes Yes TRUE
#> 4 Yes No TRUE
#> 5 No Yes TRUE
#> 6 No <NA> NA
#> 7 <NA> No NA
In the last two rows I get NA not the expected result FALSE. Expected because is.na(a) & is.na(b)
should be returning FALSE, as they appear to in the example below.
# False as expected here
if_else(is.na(NA) & is.na("No"),NA,FALSE)
#> [1] FALSE
Am I missing something about the way if_else
works?
Created on 2019-02-06 by the reprex package (v0.2.1)
Upvotes: 1
Views: 85
Reputation: 887231
We need to add the condition in the first if_else
to take care of the NA
elements, otherwise, a comparison with NA
elements returns NA
df1 %>%
mutate(logical = if_else((a == "Yes" & !is.na(a)) |
(b == "Yes" & !is.na(b)), TRUE,
if_else(is.na(a) & is.na(b), NA, FALSE )))
# a b logical
#1 <NA> <NA> NA
#2 No No FALSE
#3 Yes Yes TRUE
#4 Yes No TRUE
#5 No Yes TRUE
#6 No <NA> FALSE
#7 <NA> No FALSE
NOTE: Here, we are trying to resolve the OP's underlying issue
Also, we can replace ==
with %in%
and NA
issue will be resolved
df1 %>%
mutate(logical = if_else(a %in% "Yes" | b %in% "Yes", TRUE,
if_else(is.na(a) & is.na(b), NA, FALSE)))
Or using base R
replace((rowSums(df1 == "Yes", na.rm = TRUE) > 0), rowSums(is.na(df1) == 2, NA)
#[1] NA FALSE TRUE TRUE TRUE FALSE FALSE
df1 <- data.frame(
"a"=c(NA,"No","Yes","Yes","No","No",NA),
"b"=c(NA,"No","Yes","No","Yes",NA,"No")
)
Upvotes: 0
Reputation: 14764
You could also do:
library(dplyr)
data.frame(
"a"=c(NA,"No","Yes","Yes","No","No",NA),
"b"=c(NA,"No","Yes","No","Yes",NA,"No")
) %>%
mutate(
logical = case_when(
a == "Yes" | b == "Yes" ~ TRUE,
is.na(a) & is.na(b) ~ NA,
TRUE ~ FALSE
)
)
Output:
a b logical
1 <NA> <NA> NA
2 No No FALSE
3 Yes Yes TRUE
4 Yes No TRUE
5 No Yes TRUE
6 No <NA> FALSE
7 <NA> No FALSE
Upvotes: 3