R: Ifelse Function Returns Vector Position Instead of Value (String)

R: ifelse function returns vector position instead of value (string)

The field answer is factor, hence your function returns number (level of factor).

What you need to do is:

aDDs$answer <- as.character(aDDs$answer)

and then it works.

return value of ifelse from another vector via index

To explain this strange behaviour the source code of ifelse is helpful (see below).

As soon as you call ifelse the expressions passed as the arguments test, yes and no are evaluated resulting in:

Browse[2]> test
[1] FALSE FALSE TRUE FALSE FALSE FALSE TRUE FALSE FALSE
Browse[2]> yes
[1] "a" "b" "c" NA "a" "b" "c" NA
Browse[2]> no
[1] 0 1 2 3 4 1 2 3 4

Observe that y[x] uses the values of x to pick values from y
and the value 0 is empty (= ignored) , values above 3 are NA,
that is why the `yes´ argument becomes

[1] "a" "b" "c" NA "a" "b" "c" NA

The code line

ans[test & ok] <- rep(yes, length.out = length(ans))[test & ok]

is then applied at the end and effectivly does update all TRUE-elements using the test logical vector:

yes[test]

which results in:

[1] "c" "c"

being stored in the result indices 3 and 7

ans[test & ok]

So the problem is using y[x] as second argument to ifelse + the non-intuitive ifelse behaviour to use a logical index to pick the "TRUE"-results from y[x]...

Lesson learned: Avoid complicated ifelse logic, it has lot of side effects (eg. you may loose the correct data type or attributes).

# ifelse function
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) {
yat <- attributes(yes)
if (is.null(yat) || (is.function(yes) && identical(names(yat),
"srcref")))
return(yes)
}
}
else if (length(no) == 1) {
nat <- attributes(no)
if (is.null(nat) || (is.function(no) && identical(names(nat),
"srcref")))
return(no)
}
}
}
else test <- if (isS4(test))
methods::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
}

Why can't R's ifelse statements return vectors?

The documentation for ifelse states:

ifelse returns a value with the same
shape as test which is filled with
elements selected from either yes or
no depending on whether the element
of test is TRUE or FALSE.

Since you are passing test values of length 1, you are getting results of length 1. If you pass longer test vectors, you will get longer results:

> ifelse(c(TRUE, FALSE), c(1, 2), c(3, 4))
[1] 1 4

So ifelse is intended for the specific purpose of testing a vector of booleans and returning a vector of the same length, filled with elements taken from the (vector) yes and no arguments.

It is a common confusion, because of the function's name, to use this when really you want just a normal if () {} else {} construction instead.

ifelse function returns numbers instead of dates

Basically, the new column should be treaty date y, if available, otherwise treaty date x, otherwise nothing. Another option

ResSet2$Treaty_Date=ResSet2$Treaty_Date.y
ResSet2$Treaty_Date[is.na(ResSet2$Treaty_Date)]=
ResSet2$Treaty_Date.x[is.na(ResSet2$Treaty_Date)]

Treaty_Date.x Treaty_Date.y Treaty_Date
1 2020-12-31 <NA> 2020-12-31
2 <NA> 2019-05-22 2019-05-22
3 2020-10-13 2019-09-01 2019-09-01

ifelse function on a vector

ifelse is vectorized and its result is as long as the test argument. all(is.na(vect)) is always just length one, hence the result. a regular if/else clause is fine here.

vect <- c("NA_NA", "14_mter", "78_ONHY")

if (all(is.na(vect))) {
out <- vect
} else {
out <- vect[vect != "NA_NA"]
}
out
#> [1] "14_mter" "78_ONHY"

additional note: no need for the which() here

Why does ifelse() return an integer value that is NOT a true or false argument r

You have factor columns in the data. Your problem would be solved if you stringsAsFactors = FALSE while constructing the dataframe.

df <- data.frame (a = c(rep("c",4), (rep(NA,4))), 
b = c(rep(NA,4),rep("e",4)), stringsAsFactors = FALSE)

However, dplyr has a nice coalesce function which does exactly does what you need without using ifelse.

library(dplyr)
df %>% mutate(ab = coalesce(a, b))

Conditional assignment of value - is ifelse() the best when condition and intended return value don't have same features? [R]

We can use if/else instead of ifelse

alphabet <- if('B' %in% letters) letters else LETTERS


Related Topics



Leave a reply



Submit