Упорядочить строки данных в соответствии с вектором с определенным порядком


158

Есть ли более простой способ убедиться, что строки фрейма данных упорядочены в соответствии с «целевым» вектором, как я реализовал в коротком примере ниже?

df <- data.frame(name = letters[1:4], value = c(rep(TRUE, 2), rep(FALSE, 2)))

df
#   name value
# 1    a  TRUE
# 2    b  TRUE
# 3    c FALSE
# 4    d FALSE

target <- c("b", "c", "a", "d")

Это кажется слишком сложным, чтобы выполнить работу:

idx <- sapply(target, function(x) {
    which(df$name == x)
})
df <- df[idx,]
rownames(df) <- NULL

df 
#   name value
# 1    b  TRUE
# 2    c FALSE
# 3    a  TRUE
# 4    d FALSE

Ответы:


232

Попробуй match:

df <- data.frame(name=letters[1:4], value=c(rep(TRUE, 2), rep(FALSE, 2)))
target <- c("b", "c", "a", "d")
df[match(target, df$name),]

  name value
2    b  TRUE
3    c FALSE
1    a  TRUE
4    d FALSE

Это будет работать до тех пор, пока ваш targetсодержит точно такие же элементы, какdf$name , что и оба, и не содержат повторяющихся значений.

От ?match:

match returns a vector of the positions of (first) matches of its first argument 
in its second.

Поэтому matchнаходит номера строк, которые соответствуют targetэлементам, и затем мы возвращаемся dfв этом порядке.


Отлично, это больше похоже на то, что я искал! Большое спасибо
Раппстер

1
один вопрос, что если столбец, который я бы хотел сопоставить, имеет повторяющиеся значения? как b,c,a,d,b,c,a,d. Я пытался, matchно это не работает хорошо.
Юлонг

@Yulong: я думаю, что вам нужно явно убедиться, что дубликаты удаляются до увольнения match(). Что приходит на ум duplicated(), unique()или какая-то другая обычная процедура, которая «сохраняет» нужные элементы, отбрасывая другие. HTH
Раппстер

@ Эдвард, это хорошее решение. Однако это также меняет показатели. Как я могу также держать их в порядке возрастания (1, 2, 3, 4)?
Хасан Икбал

2
не уверен, что это самый чистый способ, но с только «базовыми» функциями, это должно работать, если у вас есть дубликаты в df:df <- data.frame(name=letters[c(1:4, 1:4)], value=c(rep(TRUE, 2), rep(FALSE, 2),rep(TRUE, 2), rep(FALSE, 2) )) target <- c("b", "c", "a", "d") df[order(unlist(sapply(df$name, function(x) which(target == x)))),]
Erica

21

Я предпочитаю использовать ***_join в dplyrслучаях , когда мне нужно , чтобы соответствовать данным. Одна из возможных попыток для этого

left_join(data.frame(name=target),df,by="name")

Обратите внимание, что для ввода ***_joinтребуется tbls или data.frame


Да, функции * _join dplyrдействительно хороши. В
конечном итоге

В этом случае рекомендуется объявлять целевой порядок в виде таблицы, чтобы избежать преобразования data.frame () в факторы. target <- tibble(name = c("b", "c", "a", "d"))
крапива

2
И с синтаксисом канала: df %>% right_join(tibble(name = target), by = "name")
Фрэнк

18

Этот метод немного отличается, он предоставил мне немного больше гибкости, чем предыдущий ответ. Превратив его в упорядоченный фактор, вы можете красиво использовать его arrangeи тому подобное. Я использовал reorder.factor из gdataпакета.

df <- data.frame(name=letters[1:4], value=c(rep(TRUE, 2), rep(FALSE, 2)))
target <- c("b", "c", "a", "d")

require(gdata)
df$name <- reorder.factor(df$name, new.order=target)

Далее используйте тот факт, что теперь он заказан:

require(dplyr)
df %>%
  arrange(name)
    name value
1    b  TRUE
2    c FALSE
3    a  TRUE
4    d FALSE

Если вы хотите вернуться к исходному (алфавитному) порядку, просто используйте, as.character()чтобы вернуть его в исходное состояние.


2
Кто-нибудь знает версию этого data.table?
Рейльштейн

2
@Reilstein setDT(df)[ , name := factor(name, levels = target)]. Тогда посмотрите два data.tableответа здесь
Хенрик

4

Мы можем настроить уровни факторов на основе targetи использовать его вarrange

library(dplyr)
df %>% arrange(factor(name, levels = target))

#  name value
#1    b  TRUE
#2    c FALSE
#3    a  TRUE
#4    d FALSE

Или orderэто и использовать его вslice

df %>% slice(order(factor(name, levels = target)))

2
Лучшее решение IMO
stevec

1
Лучшие и самые простые решения для меня.
Matt_B

0

Если вы не хотите использовать какую - либо библиотеку , и вы должны reoccurrences в ваших данных, вы можете использовать whichс sapplyа.

new_order <- sapply(target, function(x,df){which(df$name == x)}, df=df)
df        <- df[new_order,]
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.