39

Here is a vector

a <- c(TRUE, FALSE, FALSE, NA, FALSE, TRUE, NA, FALSE, TRUE)

I'd like a simple function that returns TRUE everytime there is a TRUE in "a", and FALSE everytime there is a FALSE or a NA in "a".

The three following things do not work

a == TRUE
identical(TRUE, a)
isTRUE(a)

Here is a solution

a[-which(is.na(a))]

but it doesn't seem to be a straightforward and easy solution

Is there another solution ?

Here are some functions (and operators) I know:

identical()
isTRUE()
is.na()
na.rm()
&
|
!
  • What are the other functions (operators, tips, whatever,...) that are useful to deal with TRUE, FALSE, NA, NaN?

  • What are the differences between NA and NaN?

  • Are there other "logical things" than TRUE, FALSE, NA and NaN?

Thanks a lot !

Gregor Thomas
  • 136,190
  • 20
  • 167
  • 294
Remi.b
  • 17,389
  • 28
  • 87
  • 168
  • 6
    To answer your first question, here is one way: `Vectorize(isTRUE)(a)`. – Matthew Plourde May 29 '13 at 19:43
  • 1
    more narrowly, I think `!is.na(x) & x` should work, as long as the values you're expecting are definitely contained in {`TRUE`, `FALSE`, `NA`, `NaN`} ... – Ben Bolker May 29 '13 at 19:50
  • I feel like some of these distinctions (`NA` vs `NaN`, `isTRUE` vs `is.na`, etc.) must have been discussed elsewhere/previously, maybe even on StackOverflow. Googling "na nan is.finite is.nan is.na" gets me to http://stat.ethz.ch/R-manual/R-devel/library/base/html/is.finite.html , which oddly doesn't have a "See also" to http://stat.ethz.ch/R-manual/R-devel/library/base/html/NA.html – Ben Bolker May 29 '13 at 19:58
  • for completeness, I would add `all.equal`, `is.finite`, and `is.nan` to your list above ... – Ben Bolker May 29 '13 at 20:01
  • 4
    NaN is numeric so you can't encounter it in a logical vector. The proposed solution `a[-which(is.na(a))]` has only 7 elements whereas `a` has 9 elements. Are you sure that is what you want? Maybe `sapply(a, isTRUE)` is what you want? – G. Grothendieck May 29 '13 at 20:02
  • Just a quick, tangential comment regarding the last portion of the question: "Are there other "logical things" than T,F,NA and NaN?" -- `T` and `F` are **not**, generally speaking, equal to `TRUE` and `FALSE`; i.e., they are not reserved words and can be redefined at any time by the user. This means that you need to be careful treating them as such; e.g., `T <- FALSE` could really ruin your day. – Jason Morgan May 29 '13 at 21:01

5 Answers5

69

You don't need to wrap anything in a function - the following works

a = c(T,F,NA)

a %in% TRUE

[1]  TRUE FALSE FALSE
wjchulme
  • 1,928
  • 1
  • 18
  • 28
  • 11
    Nice solution. You can use it in functional form: `'%in%'(aamc$forgive, FALSE)` which is useful for `apply` and its ilk. – Ari B. Friedman Feb 07 '15 at 17:26
  • Very nice and useful solution when trying to build functions that will not throw errors etc. when using logical tests involving ">=", "<=", "==", etc. when it might be evaluated against a NA. – Jim Maas Jun 14 '20 at 06:48
17

To answer your questions in order:

1) The == operator does indeed not treat NA's as you would expect it to. A very useful function is this compareNA function from r-cookbook.com:

  compareNA <- function(v1,v2) {
    # This function returns TRUE wherever elements are the same, including NA's,
    # and false everywhere else.
    same <- (v1 == v2)  |  (is.na(v1) & is.na(v2))
    same[is.na(same)] <- FALSE
    return(same)
   }

2) NA stands for "Not available", and is not the same as the general NaN ("not a number"). NA is generally used for a default value for a number to stand in for missing data; NaN's are normally generated because a numerical issue (taking log of -1 or similar).

3) I'm not really sure what you mean by "logical things"--many different data types, including numeric vectors, can be used as input to logical operators. You might want to try reading the R logical operators page: http://stat.ethz.ch/R-manual/R-patched/library/base/html/Logic.html.

Hope this helps!

ben
  • 467
  • 3
  • 11
  • Division by 0 is `Inf`, but `Inf - Inf` gives you `NaN`. A lot of times R functions will raise an exception if `NaN`s are generated, e.g., `log(-1)`. – Matthew Plourde May 29 '13 at 20:03
  • eq = function(x,y) is.element(x == y, TRUE) | is.na(x) & is.na(y) – JRC Mar 04 '22 at 11:24
10

So you want TRUE to remain TRUE and FALSE to remain FALSE, the only real change is that NA needs to become FALSE, so just do this change like:

a[ is.na(a) ] <- FALSE

Or you could rephrase to say it is only TRUE if it is TRUE and not missing:

a <- a & !is.na(a)
Greg Snow
  • 48,497
  • 6
  • 83
  • 110
7

Taking Ben Bolker's suggestion above you could set your own function following the is.na() syntax

is.true <- function(x) {
  !is.na(x) & x
}

a = c(T,F,F,NA,F,T,NA,F,T)

is.true(a)
[1]  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE  TRUE

This also works for subsetting data.

b = c(1:9)
df <- as.data.frame(cbind(a,b))

df[is.true(df$a),]

  a b
1 1 1
6 1 6
9 1 9

And helps avoid accidentally incorporating empty rows where NA do exist in the data.

df[df$a == TRUE,]

      a  b
1     1  1
NA   NA NA
6     1  6
NA.1 NA NA
9     1  9
JWilliman
  • 3,558
  • 32
  • 36
  • you really don't need the `ifelse()` here -- as @GregSnow's answer points out, `!is.na(x) & x` is equivalent – Ben Bolker Nov 19 '14 at 15:47
  • Ben, I really agree with this, and it works but it is not straight forward to follow the logic because you get into double and triple negatives paradigm .... which many of us find hard to follow. Is there not a better, more direct way that does not depend on double negatives ? – Jim Maas Jun 14 '20 at 06:52
7

I like the is.element-function:

is.element(a, T)
skeletor
  • 361
  • 1
  • 3
  • 8