Edit:
See below for details but you can do this in a single apply
loop:
apply( mat , 2 , function(x) colSums( x > mat )
apply
is fast here, because is optimised to work on matrices. A lot of the time spent using apply
is usually in the conversion of a data.frame
to a matrix which is not needed here.
Original:
It's possible to do this entirely vectorised because >
has an method for matrices
and data.frame
s. Therefore you can get the indices of columns to compare using expand.grid()
, use this to subset the matrix, do the logical comparison and then use colSums
to get the result and matrix
to wrap it back up to the correct size. All this in 4 lines (really it could be 2):
n <- 1:ncol(mat)
ind <- expand.grid(n,n)
out <- colSums( mat[,c(ind[,1])] > mat[,c(ind[,2])] )
matrix( out , ncol(mat) , byrow = TRUE )
# [,1] [,2] [,3] [,4] [,5]
#[1,] 0 1 0 0 0
#[2,] 2 0 1 1 2
#[3,] 3 2 0 2 2
#[4,] 2 3 1 0 1
#[5,] 3 2 1 1 0
Update:
apply
seems even faster, and combining apply
with @Ricardo's comparison of the whole matrix
leads us to a single, fastest (?) apply
solution which is approximately 4 times quicker than the OP:
# Single apply loop
f1 <- function(mat) apply( mat , 2 , function(x) colSums( x > mat ) )
# OP double apply loop
f2 <- function(mat) {apply(mat, MARGIN = 2,
function(x) {
return(apply(mat, MARGIN = 2, function(y) {
return(sum(x > y))
}))})}
require(microbenchmark)
microbenchmark( f1(mat) , f2(mat) )
#Unit: microseconds
# expr min lq median uq max neval
# f1(mat) 95.190 97.6405 102.7145 111.4635 159.584 100
# f2(mat) 361.862 370.7860 398.7830 418.3810 1336.506 100