How to treat NAs like values when comparing elementwise in R
I like this one, since it is pretty simple and it's easy to see that it works (source):
# This function returns TRUE wherever elements are the same, including NA's,
# and FALSE everywhere else.
compareNA <- function(v1, v2)
{
same <- (v1 == v2) | (is.na(v1) & is.na(v2))
same[is.na(same)] <- FALSE
return(same)
}
Here is another solution. It's probably slower than my other answer because it's not vectorised, but it's certainly more elegant. I noticed the other day that %in%
compares NA
like other values. Thus c(1L, NA) %in% 1:4
gives TRUE FALSE
rather than TRUE NA
, for example.
So you can have:
!mapply(`%in%`, a, b)
Taking advantage of the fact that:
T & NA = NA
but
F & NA = F
and
F | NA = NA
but
T | NA = T
The following solution works, with carefully placed brackets:
(a != b | (is.na(a) & !is.na(b)) | (is.na(b) & !is.na(a))) & !(is.na(a) & is.na(b))
You could define:
`%!=na%` <- function(e1, e2) (e1 != e2 | (is.na(e1) & !is.na(e2)) | (is.na(e2) & !is.na(e1))) & !(is.na(e1) & is.na(e2))
and then use:
a %!=na% b
We could perform an on-the-fly replacement of the NA values with a value v1
which is not present in both the vectors and do the !=
f1 <- function(x, y) {
v1 <- setdiff(1:1000, na.omit(unique(c(x,y))))[1]
replace(x, is.na(x), v1) != replace(y, is.na(y), v1)
}
f1(a,b)
#[1] FALSE TRUE TRUE TRUE FALSE
f1(a1,b1)
#[1] TRUE TRUE TRUE
f1(a2,b2)
#[1] FALSE TRUE TRUE FALSE
data
a <- c(1, NA, 2, 2, NA)
b<-c(1, 1, 1, NA, NA)
a1 <- c(NA, 1, NA)
b1 <- c(2, NA, 3)
a2<-c(1,NA,2,NA)
b2<-c(1,1,3,NA)