Home > Back-end >  ifelse() combined with stop() throws unexpected error (R)
ifelse() combined with stop() throws unexpected error (R)

Time:10-30

I want to create a new column in a data.table with some nested ifelse() statements: I included a control with stop() at the end, which should never be reached. In my exampled either condition_a or condition_b has to be "Y". The stop() should never be reached, but it does. Can someone explain this to me?

Example code:

library(data.table)

condition_a <- c("Y", "Y", "Y", "Y", "Y", "Y")
condition_b <- c("Y", "Y", "Y", "Y", "Y", "N")

dt <- data.table(condition_a, condition_b)

dt <-
  dt[, conditions := ifelse(test = ((condition_a == "Y") &
                                      (condition_b == "Y")),
                            yes = "a_and_b",
                            no = ifelse(test = ((condition_a == "N") &
                                                  (condition_b == "Y")),
                                        yes = "b",
                                        no = ifelse(test = ((condition_a == "Y") &
                                                              (condition_b == "N")),
                                                    yes = "a",
                                                    no = ifelse(test = ((condition_a == "N") &
                                                                          (condition_b == "N")),
                                                                yes = stop('double "N" found'),
                                                                no = stop("this should not happen")))))]

Thanks for your help :).

CodePudding user response:

You obtained an error because ifelse often evaluates all its arguments (but not always: there are edges cases where there is no evaluation like in ifelse(test=c(1, NA)==c(NA, 1), stop("notEval"), stop("notEavl")); note that in this particular case, the test argument evaluates to only NAs).

If you would like to evaluate an argument only when it's necessary, you should use the data.table function fcase, which is a nice and smart implementation of nested ifelse.

dt[, conditions := fcase(condition_a == "Y" & condition_b == "Y", "a_and_b",
                         condition_a == "N" & condition_b == "Y", "b",
                         condition_a == "Y" & condition_b == "N", "a",
                         condition_a == "N" & condition_b == "N", stop('double "N" found'))]

In this case, the statement with stop will never be evaluated because the there is no case where condition_a == "N" & condition_b == "N" evaluates to TRUE in dt.

Also note that data.table works by reference; so, there is no need to reassign your data.table when using :=. that is, dt[, conditions := ...] will add a new column to dt. you don't need to use the assignment operator <- like in dt <- dt[, conditions := ...].

  • Related