Froom2
Froom2

Reputation: 1279

What does ifelse do with NA values?

I've got code that does what I want. I would, however, very much like to understand why it works one way and not the other.

I wanted to conditionally put new values into a new column, and wrote the following code:

test <- data.frame(Usual=c(1:3,NA,NA,4,5,7,15))

test$Active1 <- NA

test$Active1 <- ifelse(test[,"Usual"]==1|test[,"Usual"]==2|test[,"Usual"]==3,1,
                       ifelse(test[,"Usual"]==7,2,
                              ifelse(test[,"Usual"]==4|test[,"Usual"]==5|test[,"Usual"]==6|test[,"Usual"]==7,3,
                                     ifelse(is.na(test[,"Usual"]),"ROAR",":("))))

I put in the extra condition for is.na at the end, because I wasn't sure if it would get confused if I didn't do that. But it doesn't replace the NAs with "ROAR" - why?

If I put the condition for is.na at the front of the ifelse, it does what I expected it to do:

test$Active2 <- NA
  test$Active2 <- ifelse(is.na(test[,"Usual"]),"ROAR",
                         ifelse(test[,"Usual"]==7,2,
                                ifelse(test[,"Usual"]==4|test[,"Usual"]==5|test[,"Usual"]==6|test[,"Usual"]==7,3,
                                       ifelse(test[,"Usual"]==1|test[,"Usual"]==2|test[,"Usual"]==3,1,":("))))

Why does it make a difference where it's put in the ifelse? (I don't even need to use ifelse for this I know, but I was curious if it would look neater..)

Upvotes: 0

Views: 1808

Answers (2)

celiomsj
celiomsj

Reputation: 329

From the help page:

yes will be evaluated if and only if any element of test is true, and analogously for no.

In your first example, ifelse(is.na()) is never evaluated for NA rows because it fails to evaluate at the first ifelse condition.

Upvotes: 1

Bryan Hanson
Bryan Hanson

Reputation: 6213

This sort of question is most easily answered by simply typing ifelse in the R console, and the code used will be displayed. Studying the code will tell you what it does with NA.

R > ifelse
function (test, yes, no) 
{
    if (is.atomic(test)) {
        if (typeof(test) != "logical") 
            storage.mode(test) <- "logical"
        if (length(test) == 1 && is.null(attributes(test))) {
            if (is.na(test)) 
                return(NA)
            else if (test) {
                if (length(yes) == 1 && is.null(attributes(yes))) 
                  return(yes)
            }
            else if (length(no) == 1 && is.null(attributes(no))) 
                return(no)
        }
    }
    else test <- if (isS4(test)) 
        as(test, "logical")
    else as.logical(test)
    ans <- test
    ok <- !(nas <- is.na(test))
    if (any(test[ok])) 
        ans[test & ok] <- rep(yes, length.out = length(ans))[test & 
            ok]
    if (any(!test[ok])) 
        ans[!test & ok] <- rep(no, length.out = length(ans))[!test & 
            ok]
    ans[nas] <- NA
    ans
}
<bytecode: 0x1018abad0>
<environment: namespace:base>

Upvotes: 0

Related Questions