reordering alphanumeric age group in R

Viewed 61

assume this is what R gives me.

df1 = data.frame(grp = c("<2", "2-5", "21-26","27-32","6-10"), val= rep(0,5))
     grp val
1    <2   0
2   2-5   0
3 21-26   0
4 27-32   0
5  6-10   0

but I want R to understand 6 < 21 and to give:

df2 = data.frame(grp = as.factor(c("<2", "2-5", "6-10", "21-26", "27-32")), val= rep(0,5))
    grp val
1    <2   0
2   2-5   0
3  6-10   0
4 21-26   0
5 27-32   0

I tried mixedsort() from gtools but it returns indices instead of a reordered dataframe. any tips or idea how to get to this?

edit. Thanks to wonderful @akrun, I realized I must first assign his dplyr suggested answer to another object , say new_df and then pipe new_df to the rest of my code.

3 Answers

you can explicit the desired levels (and force rank order) also with base R:

grp <- factor(c("<2", "2-5", "6-10", "21-26", "27-32"),
       levels = c("<2", "2-5", "6-10", "21-26", "27-32"),
       ordered = TRUE
       )

note the use of factor not as.factor in this case

It can be easily done with parse_number to reorder the rows with arrange

library(dplyr)
df1 %>%
   arrange(readr::parse_number(grp))

-output

    grp val
1    <2   0
2   2-5   0
3  6-10   0
4 21-26   0
5 27-32   0

Or using base R

df1[do.call(order, read.csv(text = gsub("<", "-Inf,", 
    chartr("-", ",", df1$grp)), header = FALSE)),]
    grp val
1    <2   0
2   2-5   0
5  6-10   0
3 21-26   0
4 27-32   0

Not sure if this is exactly what you're looking for, but if you have a raw set of numbers you're creating a dataframe from, you can also just use cut() to create an ordered factor that aggregates your data and then table() to count frequencies within each cut range.

set.seed(100)
observations <- rnorm(20, 5, 5)
cut(observations, c(0, 2, 9, 10), include.lowest = T) |>
  table() |>
  data.frame()

#     Var1 Freq
# 1  [0,2]    2
# 2  (2,9]   16
# 3 (9,10]    1
Related