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 astest
which is filled with
elements selected from eitheryes
or
no
depending on whether the element
oftest
isTRUE
orFALSE
.
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
Programming with Ggplot2 and Dplyr
Format Axis Tick Labels to Percentage in Plotly
Plot Only One Side/Half of the Violin Plot
Is the Plyr Package for R Not Available for R Version 3.0.2
How to Insert Appendix After References in Rmd Using Rstudio
R Cmd Check Latex Error: Fatal PDFlatex - Gui Framework Cannot Be Initialized
Independently Move 2 Legends Ggplot2 on a Map
Add Font to R That Is Not in Extrafonts Library
Check Whether All Elements of a List Are in Equal in R
Control Number Formatting in Shiny's Implementation of Datatable
Manually Colouring Plots with 'Scale_Fill_Manual' in Ggplot2 Not Working
Custom Ggplot2 Axis and Label Formatting
Na Matches Na, But Is Not Equal to Na. Why
Calculating Standard Deviation Across Rows
R: Pass a List of Filtering Conditions into a Dataframe
Stacking an Existing Rasterstack Multiple Times
Does R-Server or Shiny Server Create a New R Process/Instance for Each User