do.call
需要将一个列表作为函数调用的参数。因此,您需要将矩阵的行拆分成列表。函数asplit
可以通过按其边缘拆分数组或矩阵来实现。
mt[,do.call(order, asplit(mt, 1))]
# [,1] [,2] [,3] [,4] [,5]
#[1,] 1 3 3 3 3
#[2,] 2 1 2 3 3
#[3,] 3 2 2 1 3
#[4,] 1 2 2 1 2
asplit
目前(4.2.3)通过选择切片并在 for
循环中填充列表来执行此操作。其他选项可在 将矩阵转换为列表 或 将矩阵转换为列向量列表 中找到。
比较一些可能的方法与一个更大的矩阵:
m <- matrix(sample(0:9, 1e6, TRUE), 1e3)
bench::mark(
asplit = m[,do.call(order, asplit(m, 1))],
data.frame = m[, do.call(order, data.frame(t(m)))],
splitRow = m[, do.call(order, split(m, row(m)))],
lapply = m[,do.call(order, lapply(1:nrow(m), function(i) m[i,]))],
splitNrow = m[, do.call(order, split(m, 1:nrow(m)))],
apply = m[, do.call(order, apply(m, 1, identity, simplify = FALSE))],
tapply = m[, do.call(order, tapply(m, row(m), identity))]
)
结果
expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time
<bch:expr> <bch:t> <bch:t> <dbl> <bch:byt> <dbl> <int> <dbl> <bch:tm>
1 asplit 8.44ms 9.02ms 111. 19.25MB 73.8 30 20 271ms
2 data.frame 6.88ms 7.24ms 138. 15.47MB 80.3 36 21 261.4ms
3 splitRow 19.79ms 19.98ms 48.9 31.01MB 73.3 10 15 204.6ms
4 lapply 6.79ms 6.99ms 141. 11.57MB 33.8 54 13 384.2ms
5 splitNrow 8.36ms 8.55ms 117. 7.76MB 16.3 50 7 428.8ms
6 apply 7.53ms 7.74ms 128. 15.38MB 50.6 43 17 335.9ms
7 tapply 27.64ms 28.47ms 35.4 38.73MB 165. 3 14 84.7ms
data.frame
和lapply
方法是最快的,splitNrow
分配的额外内存最少,但asplit
也不落后太多,而且更通用,适用于数组,并允许轻松更改边缘。
asplit
函数,我之前不知道它的存在。 - Wael