Reputation: 197
I would like to order and trasform the values of a matrix from the biggest to the smallest value as in this simple and replicable example :
#From :
d<- c(-2,-34,25,0,13,0,25,-2,1)
m<- matrix(d,3,3)
m
[,1] [,2] [,3]
[1,] -2 0 25
[2,] -34 13 -2
[3,] 25 0 1
# To:
m1
[,1] [,2] [,3]
[1,] 5 4 1
[2,] 6 2 5
[3,] 1 4 3
#25: biggest number therefore -->(1)
#13: second biggest one ---> (2)
# ecc ...
#-34: the smallest one ---> (6)
Any help? Thanks
Upvotes: 5
Views: 138
Reputation: 34703
An approach with base
rank
:
#get unique values, since rank itself doesn't
# seem to have an option that allows the
# ranking system you have in mind
u_m = unique(c(m))
#"merge" with match
matrix(rank(-u_m)[match(m, u_m)], nrow = 3L, ncol = 3L)
# [,1] [,2] [,3]
# [1,] 5 4 1
# [2,] 6 2 5
# [3,] 1 4 3
While base::rank
doesn't have a way to get what you want right away, we can use frank
(as noted by @eddi), an improved and efficient version of rank
in the data.table
package, like so:
library(data.table)
matrix(frank(-m, ties.method = "dense"), nrow = 3L, ncol = 3L)
Or, if the matrix part looks ugly, just pre-allocate something as a matrix, a la
m1 = m
m1[] = frank(-m, ties.method = "dense")
Upvotes: 6
Reputation: 6459
You can convert d to factor and then get rid of the levels. (This means you don't need any extra packages.)
m1 <- m
m1[]<-unclass(factor(d, levels = sort(unique(d), decreasing=TRUE)))
# alternative solutions from comments
# or levels=sort(-d), thanks, akrun
# or, to make it shorter: m1[] <- unclass(factor(-d))
# or, [eddi's suggestion using implicit conversions]: m1[] <- factor(-m)
m1
# [,1] [,2] [,3]
# [1,] 5 4 1
# [2,] 6 2 5
# [3,] 1 4 3
Upvotes: 10
Reputation: 887048
We can use dense_rank
library(dplyr)
m1 <- m
m1[] <- dense_rank(-m)
m1
# [,1] [,2] [,3]
#[1,] 5 4 1
#[2,] 6 2 5
#[3,] 1 4 3
Upvotes: 2