我在r
中有一个data.frame。从第2列开始,每4列形成一个块。我需要根据3,7,11,...元素值的顺序对这些块进行整体排序。也就是说,移动这些4列块,使其第二列值按递增顺序排列。
例如,如果我们有一个数据框如下
0 7 2 3 4 1 2 2 3 4 2 1 8 3 9 1 7
4 9 1 2 1 8 1 0 4 5 1 3 2 1 3 2 7
...
我希望结果是
0 1 2 2 3 3 9 1 7 4 2 1 8 7 2 3 4
4 1 3 2 7 5 1 3 2 8 1 0 4 9 1 2 1
...
有人可以帮助我吗?
答案 0 :(得分:1)
在每一行中,您根据每个4列块中的第一个值进行排序。这可以通过以下方式完成:
dat = rbind(c(0, 7, 2, 3, 4, 1, 2, 2, 3, 4, 2, 1, 8, 3, 9, 1, 7),
c(4, 9, 1, 2, 1, 8, 1, 0, 4, 5, 1, 3, 2, 1, 3, 2, 7))
t(apply(dat, 1, function(x) {
to.sort <- x[seq(2, ncol(dat), by=4)]
x[c(1, rep(order(to.sort), each=4)*4 - c(2, 1, 0, -1))]
}))
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13]
# [1,] 0 1 2 2 3 3 9 1 7 4 2 1 8
# [2,] 4 1 3 2 7 5 1 3 2 8 1 0 4
# [,14] [,15] [,16] [,17]
# [1,] 7 2 3 4
# [2,] 9 1 2 1
apply
的每一行都在调用dat
函数。首先,我们将每个4列块的第一个值抓取到一个名为to.sort
的变量中。然后,我们操纵order
函数的输出来构造行的索引;每个4列块都会回收c(2, 1, 0, -1)
,并使我们能够返回该块中的所有四列。
将此概括为一个函数,并不是很难将这个操作推广到任何数量的列,以便在开始s
和任何块大小b
时跳过:
order.blocks <- function(dat, s, b) {
t(apply(dat, 1, function(x) {
to.sort <- x[seq(s+1, ncol(dat), by=b)]
if (s > 0) padding <- seq(s) else padding <- NULL
x[c(padding, rep(order(to.sort), each=b)*b + seq(s+1-b, s))]
}))
}
order.blocks(dat, 1, 2)
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13]
# [1,] 0 1 2 1 8 1 7 2 3 3 4 3 9
# [2,] 4 0 4 1 3 2 1 2 7 3 2 5 1
# [,14] [,15] [,16] [,17]
# [1,] 4 2 7 2
# [2,] 8 1 9 1