如何按所有列对矩阵/数据框进行排序

4

我有一个矩阵,例如:

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个回答

8
这里是一个简洁的解决方案:
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()函数将矩阵以直观的方式转换为数据框,即每个矩阵列成为新数据框中的列表组件。从那里,您可以通过将矩阵的列表形式作为do.call()函数的第二个参数有效地将每个矩阵列传递给单个order()函数调用。这对于任何列数都适用。
这不是一个愚蠢的问题。 mat[order(as.data.frame(mat)),] 不起作用的原因是,order() 没有按行对数据框进行排序。
它不是根据从左到右排序列向量来返回数据框的行顺序(这是我的解决方案所做的),而是将数据框压缩为单个大向量并对其进行排序。
因此,实际上,order(as.data.frame(mat)) 等同于 order(mat),因为矩阵也被视为一个平坦的向量。
对于您特定的数据,这将返回 24 个索引,理论上可以用作(作为向量)原始矩阵 mat 的索引,但由于在表达式 mat[order(as.data.frame(mat)),] 中,您试图使用它们仅索引 mat 的行维度,因此一些索引超过了最高行索引,因此会出现“下标越界”错误。
请参见 ?do.call
我认为我无法比帮助页面更好地解释它;看一下示例,玩弄它们,直到你明白它的工作原理。基本上,当你想要传递给函数单次调用的参数被捕获在列表中时,你需要调用它。
你不能传递列表本身(因为这样你没有传递预期的参数,而是传递了一个包含预期参数的列表),所以必须有一个原始函数来从列表中“解包”参数进行函数调用。
这是编程语言中常见的原语,其中函数是一级对象,特别是(除了R的do.call())JavaScript的apply(),Python的(已弃用)apply()和vim的call()

我希望这不是一个愚蠢的问题:你能解释一下为什么 "mat[order(as.data.frame(mat)), ]" 不起作用吗?我只是不太明白 "do.call()"。在什么情况下应该考虑使用它? - wen

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