4

According to the documentation of the dplyr package:

# The _if() variants apply a predicate function (a function that
# returns TRUE or FALSE) to determine the relevant subset of
# columns.
# mutate_if() is particularly useful for transforming variables from
# one type to another
iris %>% mutate_if(is.factor, as.character)

So how do I use the inverse form? I would like to transform all non-numeric values to characters, so I thought of doing:

iris %>% mutate_if(!is.numeric, as.character)
#> Error in !is.numeric : invalid argument type

But that doesn't work. Or just select all variables that are not numeric:

iris %>% select_if(!is.numeric)
#> Error in !is.numeric : invalid argument type

Doesn't work either.

How do I use negation with dplyr functions like mutate_if(), select_if() and arrange_if()?


EDIT: This might be solved in the upcoming dplyr 1.0.0: NEWS.md.

MS Berends
  • 4,489
  • 1
  • 40
  • 53

2 Answers2

5

We can use shorthand notation ~ for anonymous function in tidyverse

library(dplyr)
iris %>% 
     mutate_if(~ !is.numeric(.), as.character)

Or without anonymous function, use negate from purrr

library(purrr)
iris %>%
     mutate_if(negate(is.numeric), as.character)

In addition to negate, Negate from base R also works

iris %>%
   mutate_if(Negate(is.numeric), as.character)

Same notation, works with select_if/arrange_if

iris %>%
     select_if(negate(is.numeric))%>%
     head(2)
#  Species
#1  setosa
#2  setosa
akrun
  • 874,273
  • 37
  • 540
  • 662
  • 1
    Great options, many thanks! Still, `select_if(!is.numeric)` would be nice. I guess I'll go for `Negate()` for now. – MS Berends Feb 10 '20 at 13:28
1

Could be a nice suggestion to add to their package, so feel free to open an issue on GitHub.

For now, you can write a function 'on-the-fly':

iris %>% mutate_if(function(x) !is.numeric(x), as.character)
iris %>% select_if(function(x) !is.numeric(x))

And this might even be safer, not sure how the _if() internals work:

iris %>% mutate_if(function(...) !is.numeric(...), as.character)
iris %>% select_if(function(...) !is.numeric(...))
MS Berends
  • 4,489
  • 1
  • 40
  • 53