which.max ties method in R

25,783

Solution 1

You could do like this:

x<-c(1,2,1,4,3,4)
#identical to which.max, except returns all indices with max
which(x==max(x)) 
[1] 4 6
z<-which(x==max(x))
z[length(z)]
[1] 6
#or with tail
tail(which(x==max(x)),1)
[1] 6

edit:

Or, you could also use max.col function for vectors like this:

max.col(t(x),"last")
[1] 6
#or
max.col(matrix(x,nrow=1),"last")
[1] 6

edit: Some benchmarking:

x<-sample(1:1000,size=10000,replace=TRUE)
library(microbenchmark)
microbenchmark(which.max(x),{z<-which(x==max(x));z[length(z)]}, 
     tail(which(x==max(x)),1),max.col(matrix(x,nrow=1),"last"),
     max.col(t(x),"last"),which.max(rev(x)),times=1000)
Unit: microseconds
                                             expr     min      lq  median      uq       max neval
                                     which.max(x)  29.390  30.323  30.323  31.256 17550.276  1000
 {     z <- which(x == max(x))     z[length(z)] }  40.586  42.452  42.919  44.318   631.178  1000
                      tail(which(x == max(x)), 1)  57.380  60.646  61.579  64.844   596.657  1000
             max.col(matrix(x, nrow = 1), "last") 134.353 138.085 139.485 144.383   710.949  1000
                            max.col(t(x), "last") 116.159 119.425 121.291 125.956   729.610  1000
                                which.max(rev(x))  89.569  91.435  92.368  96.566   746.404  1000

So all methods seem to be slower than the original (which gives wrong result), but z <- which(x == max(x));z[length(z)] seems to be fastest option of these.

Solution 2

You could reverse x

which.max(rev(x))
which.min(rev(x))

Solution 3

The which function has an 'arr.ind' parameter normally set to FALSE but usefully set to TRUE in this case:

x <- sample(1:20, 50, repl=TRUE)

> which(x==max(x), arr.ind=TRUE)
[1] 11 23
> tail(which(x==max(x), arr.ind=TRUE) , 1)
[1] 23

Using the arr.ind argument is particularly useful with matrix or array structures, but it does work with atomic vectors as well.

Solution 4

To expand on Jouni's answer, you could instead use max on the result of which:

x <- c(1, 2, 1, 4, 3, 4)
which(x == max(x)) 
[1] 4 6
max(which(x == max(x)))
[1] 6

Benchmarking:

x <- sample(1:1000, size = 10000, replace = TRUE)
library(microbenchmark)
microbenchmark(which.max(x), {z <- which(x == max(x)); z[length(z)]}, 
               tail(which(x == max(x)), 1), max.col(matrix(x, nrow = 1), "last"),
               max.col(t(x), "last"), which.max(rev(x)), max(which(x == max(x))), times = 1000)
Unit: microseconds
                                             expr     min      lq       mean  median      uq      max neval
                                     which.max(x)   6.322   6.717   7.171838   7.112   7.112   40.297  1000
 {     z <- which(x == max(x))     z[length(z)] }  27.260  28.445  37.126964  28.840  29.630 2276.346  1000
                      tail(which(x == max(x)), 1)  35.952  37.927  45.198484  38.718  40.298 1005.038  1000
             max.col(matrix(x, nrow = 1), "last") 160.791 162.766 181.698171 163.557 169.087 1688.494  1000
                            max.col(t(x), "last")  84.149  86.124 100.249921  86.915  89.680 1230.618  1000
                                which.max(rev(x))  53.729  55.310  69.442985  56.100  57.680 1076.149  1000
                          max(which(x == max(x)))  26.865  27.655  35.552256  28.050  28.841 1029.137  1000
Share:
25,783
Omar Wagih
Author by

Omar Wagih

Updated on May 04, 2020

Comments

  • Omar Wagih
    Omar Wagih about 4 years

    which.max and which.min will return the smallest index of the max or min value if there are ties.

    Is there a way around this so that the largest index is returned without affecting the efficiency of the function?

    max.col has this exact functionality, but I am dealing with a vector not a matrix.

  • Omar Wagih
    Omar Wagih about 11 years
    Benchmarking is beautiful! Thank you, I think I'll go with option 2! ` z <- which(x == max(x)) z[length(z)]`
  • Arun
    Arun about 11 years
    DWin, is there a difference in setting arr.ind=TRUE for vectors?
  • IRTFM
    IRTFM about 11 years
    I don't think so. I probably should just have used which. Sometimes I over-think.