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

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

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

3 ответов


попробовать 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 в таком порядке.

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

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(), чтобы вернуть его в исходное состояние.


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

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

обратите внимание, что вход для ***_join требуется tbls или данные.кадр