I have a matrix like below but with n rows
set.seed(123)
mt <- replicate(5, sample(1:3, 4, replace = TRUE))
mt
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 3 3 3 1 3
#> [2,] 3 2 1 2 3
#> [3,] 3 2 2 3 1
#> [4,] 2 2 2 1 1
To sort it row by row, I am using this code with the order function, similar to here:
od2 <- order(mt[1, ], mt[2, ], mt[3, ], mt[4, ])
mt[, od2]
#> [,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
Is there any way to adapt this code to n rows? I was not successful with the second version of that answer given as a comment. I am not familiar with the do.call function.
do.call needs a list as arguments to the function call. So you need to split the rows of the matrix into a list. The function asplit can do this by split an array or matrix by its margins.
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 is currently (4.2.3) doing this by selceting the slices and filling up the list an a for loop. Other options can be found at converting a matrix to a list or Convert a matrix to a list of column-vectors.
Comparing some possible methods with a larger matrix:
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))]
)
Result
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
The methods data.frame and lapply are the fastest and splitNrow allocates the lowest amount of additional memory but asplit is not so far behind and is more general and works also for arrays and allows easy to change the margin.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With