Question

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..)

Was it helpful?

Solution

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.

OTHER TIPS

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>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top