简体   繁体   中英

Use mutate_at with nested ifelse

This will make values, which are not in columnA, NA given the conditions (using %>%).

mutate_at(vars(-columnA), funs(((function(x) {
if (is.logical(x))
  return(x)
else if (!is.na(as.numeric(x)))
  return(as.numeric(x))
else
  return(NA)
})(.))))

How can I achieve the same result using mutate_at and nested ifelse?

For example, this does not produce the same result:

mutate_at(vars(-columnA),funs(ifelse(is.logical(.),.,
ifelse(!is.na(as.numeric(.)),as.numeric(.),NA))))

Update (2018-1-5)

The intent of the question is confusing, in part, due to a misconception I had in regard to what was being passed to the function.

This is what I had intended to write:

mutate_at(vars(-columnA), funs(((function(x) {
  for(i in 1:length(x))
  {
    if(!is.na(as.numeric(x[i])) && !is.logical(x[i])) 
    {
      x[i] <- as.numeric(x[i]);
    }
    else if(!is.na(x[i]))
    {
      x[i] <- NA
    }
  }
  return(x)    
})(.))))

This is a better solution:

mutate_at(vars(-columnA), function(x) {
  if(is.logical(x)) 
      return(x)

  return(as.numeric(x))
})

ifelse may not be appropriate in this case, as it returns a value that is the same shape as the condition ie, 1 logical element. In this case, is.logical(.), the result of the condition is of length 1, so the return value will be first element of the column that is passed to the function.

Update (2018-1-6)

Using ifelse, this will return columns that contain logical values or NA as-is and it will apply as.numeric to columns otherwise.

mutate_at(vars(-columnA),funs(
ifelse(. == TRUE | . == FALSE | is.na(.),.,as.numeric(.))))

The main issue is the

else if (!is.na(as.numeric(x)))
     return(as.numeric(x)) 

The if/else works on a vector of length 1. If the length of the vector/column where the function is applied is more than 1, it is better to use ifelse . In the above, the !is.na(as.numeric(x)) returns a logical vector of length more than 1 (assuming that the number of rows in the dataset is greater than 1). The way to make it work is to wrap with all/any (depending on what we need)

f1 <- function(x) {
    if (is.logical(x))
         return(x)
      else if (all(!is.na(as.numeric(x))))
         return(as.numeric(x))
          else
       return(x) #change if needed
}

df1 %>%
    mutate_all(f1)

data

set.seed(24)
df1 <- data.frame(col1 = sample(c(TRUE, FALSE), 10, replace = TRUE),
     col2 = c(1:8, "Good", 10), col3 = as.character(1:10),
 stringsAsFactors = FALSE)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM