如何按所有列对矩阵进行排序

11

假设我有

arr = 2 1 3
      1 2 3
      1 1 2

如何将这个排序成下面的形式?

arr = 1 1 2
      1 2 3
      2 1 3

也就是说,首先按照第一列排序,然后按照第二列排序,以此类推。

4个回答

21
你需要的函数是order(我是如何得出这个结论的——我的第一反应是“排序,那什么排序?”。试了一下sort(arr),看起来是将arr作为向量进行排序而不是逐行排序。查看?sort,我看到在“相关信息”:“order用于对单个或多个变量进行排序或重新排序。”)
查看?order,我看到order(x,y,z,...)会按照x排序,通过y打破平局,进一步通过z打破平局等。太棒了 - 我只需要传入arr的每一列到order函数就行了。(甚至在?order示例部分有一个例子):
order( arr[,1], arr[,2], arr[,3] ) 
# gives 3 2 1: row 3 first, then row 2, then row 1.
# Hence:
arr[ order( arr[,1], arr[,2], arr[,3] ), ]
#     [,1] [,2] [,3]
#[1,]    1    1    2
#[2,]    1    2    3
#[3,]    2    1    3

太棒了!


但是我必须为arr中的每一列写出 arr[,i] - 如果我不知道它有多少列会有点烦人。

好吧,示例也展示了如何解决这个问题:使用do.call。基本上,你需要:

do.call( order, args )

其中args是一个包含参数的列表,用于order函数。因此,如果您可以将arr的每一列转换成一个列表,那么您就可以将其作为args使用。

一种方法是将arr转换为数据帧,然后再转换为列表--这将自动将每个元素放入列表中的一列:

arr[ do.call( order, as.list(as.data.frame(arr)) ), ]

as.list(as.data.frame()有点笨拙-当然还有其他方法可以创建一个列表,使得list [[i]]arr的第i列,但这只是其中之一。


18
这样会有效:
arr[do.call(order, lapply(1:NCOL(arr), function(i) arr[, i])), ]

它所做的是:

arr[order(arr[, 1], arr[, 2], arr[ , 3]), ]

除此之外,它允许矩阵中任意数量的列。


最后一列的顺序不是多余的吗?即1:(NCOL(arr)-1)会做同样的事情。 - mdsumner
1
不是所有矩阵都是如此,例如 arr = matrix(c(1, 1, 1, 1, 1, 1, 3, 2, 1), nrow=3) - David Robinson

2

我写了一个小函数,可以按降序排列。cols参数允许选择要排序的列和它们的顺序。

ord.mat = function(M, decr = F, cols = NULL){
    if(is.null(cols))
      cols = 1: ncol(M)
    out = do.call( "order", as.data.frame(M[,cols]))
    if (decr)
      out = rev(out)
    return(M[out,])
}

1

我也遇到了类似的问题,解决方案看起来很简单而且优雅:

t(apply(t(yourMatrix),2,sort))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接