Строки кадра данных заказа согласно вектору с определенным порядком

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

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

Ответ 1

Попробуйте 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 в этом порядке.

Ответ 2

Этот метод немного отличается, он предоставил мне немного большую гибкость, чем предыдущий ответ. Сделав его упорядоченным, вы можете использовать его в 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(), чтобы вернуть его в исходное состояние.

Ответ 3

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

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

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