我有一个带有许多固定列的数据框, 后跟可变数量的列,具体取决于输入。
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.
d3 <- d2[order(d2$key1, d2$h, -d2$ak1, -d2$ak2, -d2$ak3, -d2$ak4, -d2$ak5),] # Sort all columns by name.
d4 <- d2[order(d2[,1], d2[,2], -d2[,3], -d2[,4], -d2[,5], -d2[,6], -d2[, 7]), ] # Sort by column number.
问:如何在事先不知道列的情况下按(选择的)所有列对数据框进行降序或升序排序。
例如:
# Output d3
d3
# 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.
d6 <- d2[do.call('order', bycols), ] # select by sort keys.
编辑2 如何对不同的列进行不同方向的排序,递增,递减?
将
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
您可以运行以下代码来使用所有列进行排序。请注意,排序是通过引用进行的。请注意,该解决方案并非基于内置函数。
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)))