Search code examples
rdplyrdata-transform

Use dplyr's _if() functions like mutate_if() with a negative predicate function


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.


Solution

  • 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