如何按所有列对矩阵/ data.frame进行排序

时间:2015-04-07 03:01:29

标签: r sorting matrix

我有一个矩阵,例如:

a = rep(0:1, each=4)
b = rep(rep(0:1, each=2), 2)
c = rep(0:1, times=4)
mat = cbind(c,b,a)

我需要对此矩阵的所有列进行排序。我知道如何通过对特定列进行排序(即有限数量的列)来实现此目的。

mat[order(mat[,"c"],mat[,"b"],mat[,"a"]),]
     c b a
[1,] 0 0 0
[2,] 0 0 1
[3,] 0 1 0
[4,] 0 1 1
[5,] 1 0 0
[6,] 1 0 1
[7,] 1 1 0
[8,] 1 1 1

但是,我需要一种通用的方法来执行此操作而不调用任何列名,因为我可以有任意数量的列。如何按大量列排序?

1 个答案:

答案 0 :(得分:7)

这是一个简洁的解决方案:

mat[do.call(order,as.data.frame(mat)),];
##      c b a
## [1,] 0 0 0
## [2,] 0 0 1
## [3,] 0 1 0
## [4,] 0 1 1
## [5,] 1 0 0
## [6,] 1 0 1
## [7,] 1 1 0
## [8,] 1 1 1

as.data.frame()的调用以直观的方式将矩阵转换为data.frame,即每个矩阵列成为新data.frame中的列表组件。从那里,您可以通过将矩阵的分层形式作为order()的第二个参数传递,有效地将每个矩阵列传递给do.call()的单个调用。

这适用于任意数量的列。


这不是一个愚蠢的问题。 mat[order(as.data.frame(mat)),]不起作用的原因是因为order() 按行排序data.frames。基于从左到右排序列向量(这是我的解决方案所做的),而不是返回data.frame的行顺序,它基本上将data.frame展平为单个大向量并对其进行排序。因此,事实上,order(as.data.frame(mat))等同于order(mat),因为矩阵也被视为平面向量。对于您的特定数据,这将返回24个索引,理论上可以用于索引(作为向量)原始矩阵mat,但因为在表达式mat[order(as.data.frame(mat)),]中您尝试使用它们为了仅对mat的行维度进行索引,一些索引超过了最高行索引,因此你得到一个超出范围的"下标"错误。

?do.call。我不认为我可以比帮助页面更好地解释它;看看这些例子,与它们一起玩,直到你了解它是如何工作的。基本上,当您要传递给函数的单个调用的参数被捕获在列表中时,您需要调用它。你不能通过列表本身(因为那时你没有传递预期的参数,你传递的列表包含预期的参数),所以必须有一个原始功能"展开"函数调用列表中的参数。这是编程语言中常见的原语,其中函数是一流的对象,特别是(除了R' do.call())JavaScript apply(),Python(不推荐){ {3}}和vim' apply()