4
votes

I'm trying to reorder column in a dataframe, in a descending or ascending order, based on unique values of another column in the same dataframe within groups.

To demonstrate this below is given an example in which a dataframe has three columns. The goal is to group by the gr column, and to order the a column based on the unique value of the b column. So for example if within the gr=1 the unique value of the column b is T then I would like the column a in ascending order, and if not in descending order. The example is below

# sample dataset
df <-  data.frame(
    a = c(1,3,2,4),
    b = c(T,T,F,F),
    gr = c(1,1,2,2)
  )

# split dataset according to a grouping column
df <- df %>% split(df$gr)

# ordering function
f1 <- function(dt) {
  if (unique(dt$b) == T) {
    arrange(dt, a)
  } else {
    arrange(dt, -a)
  }
}

The desired dataset should look like this:

# order within groups based on variable b
df %>% purrr::map_df(f1) 

Can this be done without using lists or tidyr::nest ? Using a simple dplyr::group_by and dplyr::arrange it should be possible and is the best desired answer.

2
if you take a closer look at the var a you can see it has been reordered. Originally it is c(1,3,2,4), and at the end it is c(1,3,4,2)adl
a reordering has been done. Instead of 2,4; a 4,2 is requiredadl
Let's say if you have more rows and there are TRUE/FALSE for a particular group, how would the order changeakrun
df %>% arrange(gr, a * if_else(b, 1, -1))d.b
d.b this is the most simple solution that works. But I will accept Akruns since it was the fastest replyadl

2 Answers

2
votes

Here is one option with arrange alone without doing any split

library(dplyr)
df %>%
   arrange(gr, c(1, -1)[gr] * a)
#  a     b gr
#1 1  TRUE  1
#2 3  TRUE  1
#3 4 FALSE  2
#4 2 FALSE  2

or if it needs to be with 'b'

df %>% 
   arrange(gr, c(-1, 1)[(b + 1)] * a)
#  a     b gr
#1 1  TRUE  1
#2 3  TRUE  1
#3 4 FALSE  2
#4 2 FALSE  2

Here, we make use of the numeric 'gr'. If it is not numeric, create the grouping index with match and use that to change values of 'a'

df %>%
   arrange(gr, c(1, -1)[match(gr, unique(gr))] * a)
2
votes

Here is a way.

library(dplyr)

f2 <- function(dt) {
  2*as.integer(df$b) - 1
}

df %>% arrange(gr, a*f2())

If you accept the rearrangement of the column gr, remove it from arrange.

df %>% arrange(a*f2())

Edit.

Simpler?

f2 <- function(x) 2*x - 1

df %>% arrange(gr, a*f2(b))