Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Order (some) observations by specific values

I need to re-order some of the rows of my dataframe. I have a list of observations (names) that I need to be at the top. It's a string variable, and just a selection of them need to be at the top--the rest can be in their existing order.

Example dataset:

df <- data.frame(name = c("Alan", "Betty", "Clyde", "Diane", "Eric", 
                          "Francine", "George", "Harriett"), 
                 height = c(60, 68, 70, 66, 68, 70, 63, 64))

I can't order from lowest to highest or vice versa, and there's no part of the string that is unique to these observations. I only care about the order for some of the observations, not all. And for the ones I do care about, they have to be in a specific order - it's not enough for them to be in the top in the wrong order.

Long version:

df$order[df$name == "Betty"] <- 1
df$order[df$name == "Diane"] <- 2
df$order[df$name == "Alan"] <- 3
df$order[df$name == "Clyde"] <- 4
df <- arrange(df, order)
df$order <- NULL

The above code works, but there are too many observations for me to feel comfortable copy/pasting a bunch of lines.

I tried doing the above code as a for loop (looping either over a list of the names or 1:4), but I couldn't get it to work. Similar for ifelse(). lapply or sapply might work, but frankly I don't understand them.

I'm hoping someone can show me how to loop/automate my solution so it's doable for more observations or show me a different way altogether.

like image 679
Mark A-L Avatar asked Dec 11 '25 00:12

Mark A-L


2 Answers

Try match in arrange

> df %>% arrange(match(name, c("Betty", "Diane", "Alan", "Clyde")))
      name height
1    Betty     68
2    Diane     66
3     Alan     60
4    Clyde     70
5     Eric     68
6 Francine     70
7   George     63
8 Harriett     64
like image 132
ThomasIsCoding Avatar answered Dec 13 '25 16:12

ThomasIsCoding


If you have the order of the first few values in a vector nm you can relevel them so they are first:

Edit

Rather than overwrite name you can pass it directly to arrange. This will preserve name as a character vector in the output:

library(forcats)
library(dplyr)

nm <- c("Betty", "Diane", "Alan", "Clyde")

df |>
  arrange(fct_relevel(fct_inorder(name), !!nm))
#       name height
# 1    Betty     68
# 2    Diane     66
# 3     Alan     60
# 4    Clyde     70
# 5     Eric     68
# 6 Francine     70
# 7   George     63
# 8 Harriett     64

fct_inorder() will ensure the original order is preserved, while fct_relevel() will move those names to the top. Without fct_inorder() the remaining names will be in alphabetical order (which is how you have them arranged in your example anyway, but just FYI).


Original Answer

library(forcats)
library(dplyr)

nm <- c("Betty", "Diane", "Alan", "Clyde")

df |>
  mutate(name = fct_relevel(fct_inorder(name), !!nm)) |>
  arrange(name)

Note: name will be a factor variable not a character variable. To return them to character, you can pipe to mutate(name = as.character(name)).

like image 31
LMc Avatar answered Dec 13 '25 16:12

LMc



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!