Reputation: 1154
I've been stumbling around over something I feel I should know. Given a small data.frame, say:
d <- tibble(a = c(45, 1, 2, 9), b = c(3, 19, 8, 12))
> d
# A tibble: 4 x 2
a b
<dbl> <dbl>
1 45 3
2 1 19
3 2 8
4 9 12
I'd like to mutate some new variables with the result of a call to toOrdinal (from the toOrdinal library). I tried this:
d %>% mutate(
across(everything(), ~ toOrdinal::toOrdinal(.x), .names = "ord_{col}")
)
But the results aren't right:
# A tibble: 4 x 4
a b ord_a ord_b
<dbl> <dbl> <chr> <chr>
1 45 3 45th 3rd
2 1 19 1th 19rd
3 2 8 2th 8rd
4 9 12 9th 12rd
Instead, what I'd like to see is:
# A tibble: 4 x 4
a b ord_a ord_b
<dbl> <dbl> <chr> <chr>
1 45 3 45th 3rd
2 1 19 1st 19th
3 2 8 2nd 8th
4 9 12 9th 12th
The warnings()
, which are usually pretty helpful, aren't pointing me to what exactly I'm doing wrong.
Any guidance is appreciated!
Upvotes: 1
Views: 33
Reputation: 887821
The function is not Vectorized
. Either we use rowwise
or Vectorize
the function
library(dplyr)
library(toOrdinal)
d %>%
mutate(across(everything(), ~ Vectorize(toOrdinal)(.),.names = "ord_{col}"))
-output
# A tibble: 4 x 4
# a b ord_a ord_b
# <dbl> <dbl> <chr> <chr>
#1 45 3 45th 3rd
#2 1 19 1st 19th
#3 2 8 2nd 8th
#4 9 12 9th 12th
Or use rowwise
d %>%
rowwise() %>%
mutate(across(everything(), ~ toOrdinal(.), .names = "ord_{col}")) %>%
ungroup
-output
# A tibble: 4 x 4
# a b ord_a ord_b
# <dbl> <dbl> <chr> <chr>
#1 45 3 45th 3rd
#2 1 19 1st 19th
#3 2 8 2nd 8th
#4 9 12 9th 12th
Or another option is to do the rowwise with pmap
from purrr
and bind the output tibble with the original dataset
library(purrr)
library(stringr)
pmap_dfr(d, ~ map_dfr(list(...), toOrdinal)) %>%
rename_all(~ str_c('ord_', .)) %>%
bind_cols(d, .)
-output
# A tibble: 4 x 4
# a b ord_a ord_b
# <dbl> <dbl> <chr> <chr>
#1 45 3 45th 3rd
#2 1 19 1st 19th
#3 2 8 2nd 8th
#4 9 12 9th 12th
Upvotes: 2