Come estendere il comportamento `==` ai vettori che includono NA?




(3)

Ho completamente fallito nella ricerca di altre discussioni su R-help o Stack Overflow su questo specifico problema. Scusa se è ovvio. Credo che sto solo cercando il modo più semplice per ottenere il segno di r == per non restituire mai NA.

# Example #

# Say I have two vectors
a <- c( 1 , 2 , 3 )
b <- c( 1 , 2 , 4 )
# And want to test if each element in the first
# is identical to each element in the second:
a == b
# It does what I want perfectly:
# TRUE TRUE FALSE

# But if either vector contains a missing,
# the `==` operator returns an incorrect result:
a <- c( 1 , NA , 3 ) 
b <- c( 1 , NA , 4 )
# Here I'd want   TRUE TRUE FALSE
a == b
# But I get TRUE NA FALSE

a <- c( 1 , NA , 3 ) 
b <- c( 1 , 2 , 4 )
# Here I'd want   TRUE FALSE FALSE
a == b
# But I get TRUE NA FALSE again.

Ottengo il risultato che voglio con:

mapply( `%in%` , a , b )

Ma mapply sembra pesante.

C'è una soluzione più intuitiva a questo?


Che ne dici di usare identical() avvolto in mapply()

a <- c( 1 , 2 , 3 )
b <- c( 1 , 2 , 4 )
mapply(identical,a,b)
#[1]  TRUE  TRUE FALSE

a <- c( 1 , NA , 3 ) 
b <- c( 1 , NA , 4 )
mapply(identical,a,b)
#[1]  TRUE  TRUE FALSE

a <- c( 1 , NA , 3 ) 
b <- c( 1 , 2 , 4 )
mapply(identical,a,b)
#[1]  TRUE FALSE FALSE

Inoltre, se è necessario confrontare i risultati dei calcoli, è possibile eliminare identical() e andare con isTRUE(all.equal()) modo

mapply(FUN=function(x,y){isTRUE(all.equal(x,y))}, a, b)

che dà gli stessi risultati, ma può gestire meglio i problemi di arrotondamento. Ad esempio

a<-.3/3
b<-.1
mapply(FUN=function(x,y){isTRUE(all.equal(x,y))}, a, b)
#[1] TRUE

mapply(identical,a,b)
#[1] FALSE

Penso che quest'ultimo esempio potrebbe rovinare molte delle soluzioni proposte, ma il passaggio a all.equal anziché a == probabilmente funzionerebbe per tutti loro.


Potresti provare

replace(a, is.na(a), Inf)==replace(b, is.na(b), Inf)

O una variazione più veloce suggerita da @docendo discimus

replace(a, which(is.na(a)), Inf)==replace(b, which(is.na(b)), Inf)

Basato sui diversi scenari

1.

a <- c( 1 , 2 , 3 )
b <- c( 1 , 2 , 4 )
akrun1()
#[1]  TRUE  TRUE FALSE

2.

 a <- c( 1 , NA , 3 ) 
 b <- c( 1 , NA , 4 )
 akrun1()
 #[1]  TRUE  TRUE FALSE

3.

 a <- c( 1 , NA , 3 ) 
 b <- c( 1 , 2 , 4 )
 akrun1()
#[1]  TRUE FALSE FALSE

benchmark

set.seed(24)
a <- sample(c(1:10, NA), 1e6, replace=TRUE)
b <- sample(c(1:20, NA), 1e6, replace=TRUE)
akrun1 <- function() {replace(a, is.na(a), Inf)==replace(b, is.na(b), Inf)}
cathG <- function() {(!is.na(a) & !is.na(b) & a==b) | (is.na(a) & is.na(b))}
anthony <- function() {mapply(`%in%`, a, b)}
webb <- function() {ifelse(is.na(a),is.na(b),a==b)}
docend <- function() {replace(a, which(is.na(a)), Inf)==replace(b,
       which(is.na(b)), Inf)}

library(microbenchmark)
microbenchmark(akrun1(), cathG(), anthony(), webb(),docend(),
  unit='relative', times=20L)
#Unit: relative
#    expr        min         lq       mean     median         uq        max
#  akrun1()   3.050200   3.035625   3.007196   2.963916   2.977490   3.083658
#   cathG()   4.829972   4.893266   4.843585   4.790466   4.816472   4.939316
# anthony() 190.499027 224.389971 215.792965 217.647702 215.503308 212.356051
#    webb()  14.000363  14.366572  15.412527  14.095947  14.671741  19.735746
#  docend()   1.000000   1.000000   1.000000   1.000000   1.000000   1.000000
# neval cld
#    20 a  
#    20 a  
#    20 c
#    20 b 
#    20 a  

Un'altra opzione, ma è meglio di mapply('%in%', a , b) ?:

(!is.na(a) & !is.na(b) & a==b) | (is.na(a) & is.na(b))

Seguendo il suggerimento di @AnthonyDamico, creazione dell'operatore "mutt":

"%==%" <- function(a, b) (!is.na(a) & !is.na(b) & a==b) | (is.na(a) & is.na(b))

Modifica: o, leggermente diversa e versione più breve di @Frank (che è anche più efficiente)

"%==%" <- function(a, b) (is.na(a) & is.na(b)) | (!is.na(eq <- a==b) & eq)

Con i diversi esempi:

a <- c( 1 , 2 , 3 )
b <- c( 1 , 2 , 4 )
a %==% b
# [1]  TRUE  TRUE FALSE

a <- c( 1 , NA , 3 )
b <- c( 1 , NA , 4 )
a %==% b
# [1]  TRUE  TRUE FALSE

a <- c( 1 , NA , 3 )
b <- c( 1 , 2 , 4 )
a %==% b
#[1]  TRUE FALSE FALSE

a <- c( 1 , NA , 3 )
b <- c( 3 , NA , 1 )
a %==% b
#[1] FALSE  TRUE FALSE



r  

r