Search code examples
rtype-conversiontidyversedplyr

Converting double to integers using R tidyverse


Following How to convert column types in R tidyverse I am trying to convert doubles (numeric) into integers.

For example, using the iris data:

iris1 <- iris %>%
  mutate_at(vars(Petal.Length), integer)

The above throws an error, which I cannot understand despite following the recommended trouble shooting:

Error: Problem with `mutate()` column `Petal.Length`.
ℹ `Petal.Length = (function (length = 0L) ...`
.x invalid 'length' argument

Using the same line of code to convert to factor and the results are fine:

iris1 <- iris %>%
mutate_at(vars(Petal.Length), factor)
class(iris1$Petal.Length)

Can someone explain to me the reason for the error and how I can convert to integer. Ideally I am looking for a solution friendly to the pipe operator %>%.


Solution

  • I think the problem you are running into is that integer() creates an integer-typed vector, which is just an empty place-holder for integers to go into. What you want is as.integer(), which takes an existing numeric vector and coerces each element into an integer. It's a minor distinction, so it's easy to miss. Here is your code with the fix implemented:

    A technically correct answer

    iris1 <- iris %>%
      mutate_at(vars(Petal.Length), as.integer) # note the AS.INTERGER()
    

    A more modern approach

    You might be interested to know that mutate_at() has been superseded by the more modern mutate(across(...))) approach. Depending on your goals, you might prefer the more modern way to solve this problem with dplyr:

    iris2 <- iris %>% 
      mutate(across(
        .cols = matches('Petal.Length'),
        .fns = ~ as.integer(.x)))
    

    Don't forget about rounding

    Just a heads up, coercing something into an integer drops any decimal values, which is basically like rounding down every value to the nearest (lower) integer. You might want to round your numbers first, then coerce them to integer format, depending on your other goals for this code.

    iris1 <- iris %>%
      mutate_at(vars(Petal.Length), ~ as.integer(round(.x)))
    

    OR

    iris2 <- iris %>% 
      mutate(across(
        .cols = matches('Petal.Length'),
        .fns = ~ round(as.integer(.x))))