Home > Blockchain >  How to arrange only some rows of a dataframe, based on a condition without affecting the rest of the
How to arrange only some rows of a dataframe, based on a condition without affecting the rest of the

Time:01-13

i have a data frame like this:

df <- tibble::tribble(
   ~COLOR, ~NUMBER, ~VALUE,
  "BLACK",      1L,   100L,
  "BLACK",      2L,   200L,
   "BLUE",      1L,   100L,
   "BLUE",      2L,   500L,
   "BLUE",      3L,   600L,
    "RED",      1L,   200L,
    "RED",      2L,   300L)

I would like to arrange only the rows labeled "BLUE" in the COLOR column in descending order by the value of the NUMBER column, without modifying the position or order of the other rows, like this:

tibble::tribble(
    ~COLOR, ~NUMBER, ~VALUE,
    "BLACK",    1L,   100L,
    "BLACK",    2L,   200L,
    "BLUE",     3L,   600L,
    "BLUE",     2L,   500L,
    "BLUE",     1L,   100L,
    "RED",      1L,   200L,
    "RED",      2L,   300L)

It seems like an easy task, i've been trying with different some combinations of 'arrange()', 'across()', and 'group_by', but I am not getting the correct code.

I think the code might be like this:

df %>%
  group_by(COLOR) %>%
  arrange(.by_group = TRUE, if(condition == COLOR = "BLUE", true = desc(NUMBER)))

I appreciate the help. Thank you.

CodePudding user response:

If the column is numeric, we may just modify the values in 'NUMBER' to negative where COLOR is "BLUE" within arrange to order in descending

library(dplyr)
df %>% 
    arrange(factor(COLOR, levels = unique(COLOR)),
      NUMBER * c(1, -1)[(COLOR == "BLUE")   1])

-output

# A tibble: 7 × 3
  COLOR NUMBER VALUE
  <chr>  <int> <int>
1 BLACK      1   100
2 BLACK      2   200
3 BLUE       3   600
4 BLUE       2   500
5 BLUE       1   100
6 RED        1   200
7 RED        2   300

Or another option with group_by/group_modify in case the column is not numeric

df %>% 
  group_by(COLOR = factor(COLOR, levels = unique(COLOR))) %>%
  group_modify(~ .x %>% arrange(if(.y == "BLUE") desc(NUMBER) else 
       NUMBER, .by_group = TRUE)) %>% 
  ungroup

-output

# A tibble: 7 × 3
  COLOR NUMBER VALUE
  <chr>  <int> <int>
1 BLACK      1   100
2 BLACK      2   200
3 BLUE       3   600
4 BLUE       2   500
5 BLUE       1   100
6 RED        1   200
7 RED        2   300

CodePudding user response:

Without modifying the position of the other rows, you can use a base-style assignment.

df[df$COLOR == "BLUE", ] <- df %>%
  filter(COLOR == "BLUE") %>%
  arrange(desc(NUMBER))

df
# # A tibble: 7 × 3
#   COLOR NUMBER VALUE
#   <chr>  <int> <int>
# 1 BLACK      1   100
# 2 BLACK      2   200
# 3 BLUE       3   600
# 4 BLUE       2   500
# 5 BLUE       1   100
# 6 RED        1   200
# 7 RED        2   300

CodePudding user response:

Here a solution:

library(dplyr)

df %>%
  group_by(COLOR) %>%
  arrange(row_number(x = if_else(COLOR == "BLUE",-NUMBER,NUMBER )),.by_group = TRUE)
  • Related