Строки кадра данных заказа согласно вектору с определенным порядком
Есть ли более простой способ обеспечить, чтобы строки фрейма данных упорядочивались в соответствии с "целевым" вектором, как тот, который я реализовал в приведенном ниже кратком примере?
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