Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reorder factor levels within group

Tags:

r

dplyr

I would like to reorder the levels of a factor in one column, but within groups defined by a grouping column.

Simple example data set:

df <- structure(list(a_factor = structure(1:6, .Label = c("a", "b", 
"c", "d", "e", "f"), class = "factor"), group = structure(c(1L, 
1L, 1L, 2L, 2L, 2L), .Label = c("group1", "group2"), class = "factor"), 
value = 1:6), class = "data.frame", row.names = c(NA, -6L
))

> df
  a_factor  group value
1        a group1     1
2        b group1     2
3        c group1     3
4        d group2     4
5        e group2     5
6        f group2     6

More precisely, how do I reorder the factor levels, e.g. descending by value where df$group == "group1", but ascending by value where df$group == "group2", preferably in dplyr?

An expected output might be:

> df
  a_factor  group value
1        c group1     3
2        b group1     2
3        a group1     1
4        d group2     4
5        e group2     5
6        f group2     6

Although, the question is more generally about how to tackle this in dplyr.

like image 926
Joris Avatar asked Aug 28 '19 16:08

Joris


3 Answers

We can negate based on group value then order:

df %>% 
  arrange(case_when(
    group == "group1" ~ -value,
    group == "group2" ~ value))

#   a_factor  group value
# 1        c group1     3
# 2        b group1     2
# 3        a group1     1
# 4        d group2     4
# 5        e group2     5
# 6        f group2     6
like image 148
zx8754 Avatar answered Oct 12 '22 23:10

zx8754


The following is a base R solution.

sp <- split(df$value, df$group)
sp <- lapply(seq_along(sp), function(i) sort(sp[[i]], decreasing = i == 1))
df$a_factor <- factor(df$a_factor, levels = df$a_factor[unlist(sp)])

df$a_factor
#[1] a b c d e f
#Levels: c b a d e f

df[order(df$a_factor), ]
#  a_factor  group value
#3        c group1     3
#2        b group1     2
#1        a group1     1
#4        d group2     4
#5        e group2     5
#6        f group2     6
like image 23
Rui Barradas Avatar answered Oct 13 '22 00:10

Rui Barradas


To reorder the factor levels you can use forcats (part of the tidyverse), and do something like this...

library(forcats)
df2 <- df %>% mutate(a_factor = fct_reorder(a_factor,
                                            value*(-1 + 2 * (group=="group1"))))

levels(df2$a_factor)
[1] "f" "e" "d" "a" "b" "c"

This does not rearrange the dataframe itself...

df2
  a_factor  group value
1        a group1     1
2        b group1     2
3        c group1     3
4        d group2     4
5        e group2     5
6        f group2     6
like image 25
Andrew Gustar Avatar answered Oct 13 '22 01:10

Andrew Gustar