У меня есть фрейм данных с несколькими фиксированными столбцами, за которым следует переменное количество столбцов, в зависимости от ввода.
dd <- data.frame(key1=c("NED", "LTU", "LAT", "ITA"), h=c(18, 3, 2, 59)) # Two columns.
dd <- rbind(dd, dd, dd) # Example dataframe.
# Append a random number of auxiliary columns, ak1, ak2, ...
set.seed(2024); n <- sample(4:8, size=1) # Number of aux. columns.
akeys <- matrix(sample(x=c(1,2,3), size=nrow(dd) * n, replace=TRUE),
ncol=n
) # With random values 1..3.
colnames(akeys) <- paste0("ak", seq(n)) # Column names: ak1, ak2, ...
d2 <- cbind(dd, akeys) # Append n columns for sorting.
# Assuming n = 5.
id3 <- order(d2$key1, d2$h, -d2$ak1, -d2$ak2, -d2$ak3, -d2$ak4, -d2$ak5) # Sort all columns by name.
id4 <- order(d2[,1], d2[,2], -d2[,3], -d2[,4], -d2[,5], -d2[,6], -d2[, 7]) # Sort by column number.
Вопрос: Как отсортировать по убыванию или возрастанию фрейм данных по (выбору) всех столбцов, не зная заранее всех столбцов.
Например:
# Output d3
d2[id3, ]
# key1 h ak1 ak2 ak3 ak4 ak5
# 8 ITA 59 2 1 3 3 3
# 4 ITA 59 1 2 3 1 1
# 12 ITA 59 1 2 1 1 1
# 3 LAT 2 3 2 2 1 3
# 11 LAT 2 3 1 3 2 3
# 7 LAT 2 2 1 2 1 1
# 10 LTU 3 1 3 1 1 2
# 2 LTU 3 1 2 3 1 1
# 6 LTU 3 1 2 1 2 2
# 9 NED 18 3 3 1 1 1
# 5 NED 18 1 2 3 2 2
# 1 NED 18 1 2 1 2 3
Редактировать (@jay.sf). Сортировка фрейма данных по (выбору) всех столбцов в порядке возрастания или убывания:
nc <- ncol(d2) # Number of columns in d2.
bycols <- subset(d2, select = c(key1, tail(seq(nc), n)) ) # Select columns by name and index in one line.
bysort <- c(FALSE, rep(TRUE, nc-1) ) # Decending, asscending ...
idx <- do.call('order', # New sort index.
c(bycols, # List of sort keys.
decreasing=list(bysort), # Sort direction.
method='radix')
)
identical(id3, idx)
d6 <- d2[idx, ]; d6
Использование order
с do.call
.
> d2[do.call('order', d2), ]
key1 h ak1 ak2 ak3 ak4 ak5
12 ITA 59 1 2 1 1 1
4 ITA 59 1 2 3 1 1
8 ITA 59 2 1 3 3 3
7 LAT 2 2 1 2 1 1
11 LAT 2 3 1 3 2 3
3 LAT 2 3 2 2 1 3
6 LTU 3 1 2 1 2 2
2 LTU 3 1 2 3 1 1
10 LTU 3 1 3 1 1 2
1 NED 18 1 2 1 2 3
5 NED 18 1 2 3 2 2
9 NED 18 3 3 1 1 1
> d2[do.call('order', c(d2, decreasing=TRUE)), ]
key1 h ak1 ak2 ak3 ak4 ak5
9 NED 18 3 3 1 1 1
5 NED 18 1 2 3 2 2
1 NED 18 1 2 1 2 3
10 LTU 3 1 3 1 1 2
2 LTU 3 1 2 3 1 1
6 LTU 3 1 2 1 2 2
3 LAT 2 3 2 2 1 3
11 LAT 2 3 1 3 2 3
7 LAT 2 2 1 2 1 1
8 ITA 59 2 1 3 3 3
4 ITA 59 1 2 3 1 1
12 ITA 59 1 2 1 1 1
Попробуйте добавить аргумент decreasing=
для каждого столбца.
> d2[
+ do.call('order',
+ c(d2, decreasing=list(c(FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE)),
+ method='radix')),
+ ]
key1 h ak1 ak2 ak3 ak4 ak5
12 ITA 59 1 2 1 1 1
4 ITA 59 1 2 3 1 1
8 ITA 59 2 1 3 3 3
7 LAT 2 2 1 2 1 1
3 LAT 2 3 2 2 1 3
11 LAT 2 3 1 3 2 3
10 LTU 3 1 3 1 1 2
6 LTU 3 1 2 1 2 2
2 LTU 3 1 2 3 1 1
1 NED 18 1 2 1 2 3
5 NED 18 1 2 3 2 2
9 NED 18 3 3 1 1 1
@RuiBarradas Я видел сбои в кодах без кавычек чаще, чем в кодах с кавычками, поэтому с тех пор я использую кавычки ;-)
@clp, посмотрите обновление, пожалуйста.
@clp Не зная заранее столбцов, но зная направления, почему?
@jay.sf, мы знаем некоторые столбцы (например, key1), но не все. Я уточнил свой вопрос.
@clp Проверьте обновление, не уверены, соответствует ли оно вашим требованиям.
Вы можете запустить следующий код для сортировки по всем столбцам. Обратите внимание, что сортировка осуществляется по ссылке. Обратите внимание, что это решение не основано на встроенных функциях.
data.table::setorderv(d2)
key1 h ak1 ak2 ak3 ak4 ak5
12 ITA 59 1 2 1 1 1
4 ITA 59 1 2 3 1 1
8 ITA 59 2 1 3 3 3
7 LAT 2 2 1 2 1 1
11 LAT 2 3 1 3 2 3
3 LAT 2 3 2 2 1 3
6 LTU 3 1 2 1 2 2
2 LTU 3 1 2 3 1 1
10 LTU 3 1 3 1 1 2
1 NED 18 1 2 1 2 3
5 NED 18 1 2 3 2 2
9 NED 18 3 3 1 1 1
Обратите внимание, что эта функция имеет два аргумента для настройки способа сортировки и использования столбцов. Аргумент cols
указывает используемые столбцы (по умолчанию все столбцы), а аргумент order
указывает, как используется каждый столбец (в порядке возрастания или убывания); В order
1
используется для увеличения, а -1
для убывания порядка, и его длина может быть равна количеству столбцов, используемых для сортировки.
Чтобы отсортировать data.frame по возрастанию на основе первого столбца и по убыванию для остальных столбцов, можно использовать приведенный ниже код:
data.table::setorderv(d2, order=c(1, rep(-1, length(d2)-1)))
Если вы не ограничиваетесь только базой R, вы можете попробовать
d2 %>%
arrange(across(everything()))
который дает
key1 h ak1 ak2 ak3 ak4 ak5
1 ITA 59 1 2 1 1 1
2 ITA 59 1 2 3 1 1
3 ITA 59 2 1 3 3 3
4 LAT 2 2 1 2 1 1
5 LAT 2 3 1 3 2 3
6 LAT 2 3 2 2 1 3
7 LTU 3 1 2 1 2 2
8 LTU 3 1 2 3 1 1
9 LTU 3 1 3 1 1 2
10 NED 18 1 2 1 2 3
11 NED 18 1 2 3 2 2
12 NED 18 3 3 1 1 1
В Base R я сортирую подмножество исходного фрейма данных, состоящее из всех ключей, и использую полученный индекс для упорядочения исходного фрейма данных. Какова процедура в dplyr, если известен один ключ, скажем «ключ1», а остальные ключи состоят из переменного числа ak1, ak2, ..., akn, в зависимости от ввода?
Мое решение именно так. (Однако одинарные кавычки вам не нужны.)