我有一个矩阵,例如:
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
但是,我需要一种不调用任何列名的通用方法,因为我可以有任意数量的列。如何按大量列排序?
最佳答案
这是一个简洁的解决方案:
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 的(已弃用) apply()
, 和 vim 的 call()
.
关于r - 如何按所有列对矩阵/数据框进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29482983/