Reputation: 337
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 %>%
.
Upvotes: 2
Views: 7698
Reputation: 1
I ran into the same problem trying to run "uncount" on a column that had been converted from a percentage to an absolute number, so it was in effect an integer but still technically a double
# A tibble: 18 × 2
MobileOS OS_2010
<fct> <dbl>
1 Android 1190
2 BlackBerry OS 2013
3 Brew 0
4 iOS 5358
5 LG 52
6 Linux 0
7 Nintendo 79
8 Nintendo 3DS 0
9 Nokia Unknown 0
10 Other 77
11 Playstation 218
12 Samsung 174
13 Series 40 0
14 Sony Ericsson 43
15 SymbianOS 141
16 Unknown 433
17 webOS 117
18 Windows 105
Apparently you could get away with that in the old days
So I tried the older way to coerce the double to integer
df %<>%
mutate_at(vars(OS_2010), as.integer) %>%
print()
That worked, and the "uncount" worked
Then I reran the problem and used the modern way
df %<>%
mutate(across(
.cols = matches('OS_2010'),
.fns = ~ as.integer(.x)))
That worked also.
Upvotes: 0
Reputation: 370
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:
iris1 <- iris %>%
mutate_at(vars(Petal.Length), as.integer) # note the AS.INTERGER()
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)))
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))))
Upvotes: 3