Упорядочить строки данных в соответствии с вектором с определенным порядком
Есть ли более простой способ убедиться, что строки фрейма данных упорядочены по "целевому" вектору, как я реализовал в коротком примере ниже?
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
6 ответов
Пытаться 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
в этой последовательности.
Мы можем корректировать уровни факторов на основе 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)))
Я предпочитаю использовать ***_join
в dplyr
всякий раз, когда мне нужно сопоставить данные. Одна из возможных попыток для этого
left_join(data.frame(name=target),df,by="name")
Обратите внимание, что вход для ***_join
требуют таблицы или data.frame
Этот метод немного отличается, он предоставил мне немного больше гибкости, чем предыдущий ответ. Превратив его в упорядоченный фактор, вы можете использовать его в 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()
чтобы вернуть его в исходное состояние.
Если вы не хотите использовать какие-либо библиотеки и у вас есть повторения в ваших данных, вы можете использовать which
с sapply
также.
new_order <- sapply(target, function(x,df){which(df$name == x)}, df=df)
df <- df[new_order,]
Вот аналогичная система для ситуации, когда у вас есть переменная, по которой вы хотите отсортировать сначала, но затем вы хотите отсортировать по вторичной переменной в соответствии с порядком, в котором эта вторичная переменная впервые появляется в начальной сортировке.
В приведенной ниже функции исходная переменная сортировки называется
order_by
а вторичная переменная называется
order_along
- как в «порядке по этой переменной в исходном порядке».
library(dplyr, warn.conflicts = FALSE)
df <- structure(
list(
msoa11hclnm = c(
"Bewbush", "Tilgate", "Felpham",
"Selsey", "Brunswick", "Ratton", "Ore", "Polegate", "Mile Oak",
"Upperton", "Arundel", "Kemptown"
),
lad20nm = c(
"Crawley", "Crawley",
"Arun", "Chichester", "Brighton and Hove", "Eastbourne", "Hastings",
"Wealden", "Brighton and Hove", "Eastbourne", "Arun", "Brighton and Hove"
),
shape_area = c(
1328821, 3089180, 3540014, 9738033, 448888, 10152663, 5517102,
7036428, 5656430, 2653589, 72832514, 826151
)
),
row.names = c(NA, -12L), class = "data.frame"
)
это не дает мне того, что мне нужно:
df %>%
dplyr::arrange(shape_area, lad20nm)
#> msoa11hclnm lad20nm shape_area
#> 1 Brunswick Brighton and Hove 448888
#> 2 Kemptown Brighton and Hove 826151
#> 3 Bewbush Crawley 1328821
#> 4 Upperton Eastbourne 2653589
#> 5 Tilgate Crawley 3089180
#> 6 Felpham Arun 3540014
#> 7 Ore Hastings 5517102
#> 8 Mile Oak Brighton and Hove 5656430
#> 9 Polegate Wealden 7036428
#> 10 Selsey Chichester 9738033
#> 11 Ratton Eastbourne 10152663
#> 12 Arundel Arun 72832514
Вот функция:
order_along <- function(df, order_along, order_by) {
cols <- colnames(df)
df <- df %>%
dplyr::arrange({{ order_by }})
df %>%
dplyr::select({{ order_along }}) %>%
dplyr::distinct() %>%
dplyr::full_join(df) %>%
dplyr::select(dplyr::all_of(cols))
}
order_along(df, lad20nm, shape_area)
#> Joining, by = "lad20nm"
#> msoa11hclnm lad20nm shape_area
#> 1 Brunswick Brighton and Hove 448888
#> 2 Kemptown Brighton and Hove 826151
#> 3 Mile Oak Brighton and Hove 5656430
#> 4 Bewbush Crawley 1328821
#> 5 Tilgate Crawley 3089180
#> 6 Upperton Eastbourne 2653589
#> 7 Ratton Eastbourne 10152663
#> 8 Felpham Arun 3540014
#> 9 Arundel Arun 72832514
#> 10 Ore Hastings 5517102
#> 11 Polegate Wealden 7036428
#> 12 Selsey Chichester 9738033
Создано 12.01.2021 пакетом REPEX (v0.3.0)