Neal Barsch
Neal Barsch

Reputation: 2940

The index of second, third,.. min with apply function

I have a function where I am calculating the index of the minimum distance between a lat/long coordinate (in SpatialPoints) and another vector of coordinates (also in SpatialPoints). The function I use to find min dist is:

library(rgeos)
dfdist$mindist <-apply(gDistance(sp1, sp2, byid=TRUE), 1, which.min)

The function above gives me a column mindist in my pre-existing data frame dfdist which is an index of the row number of the point where the minimum distance occurs.

I'd like to also find the 2nd min distance, and the 3rd min dist, but am unsure of how to do this with the apply(). Is there a replacement for the which.min which will give me the index of the second min? Third min?

Upvotes: 1

Views: 342

Answers (2)

Benjamin
Benjamin

Reputation: 17279

I would use functions like the following:

which_nmin <- function(x, n = 1) 
{
  ux <- unique(x)
  ux <- ux[order(ux)][n]
  which(x == ux)
}

which_nmin(c(1, 1, 1, 1:5), 3)


which_nmax <- function(x, n = 1) 
{
  ux <- unique(x)
  ux <- ux[order(ux, decreasing = TRUE)][n]
  which(x == ux)
}

which_nmax(c(1, 1, 1, 1:5), 2)

Your apply call would be

apply(gDistance(sp1, sp2, byid=TRUE), 1, which_nmin, n = 2)

Upvotes: 0

989
989

Reputation: 12935

You can use this user-defined function to do so:

f_which.min <- function(vec, idx) sort(vec, index.return = TRUE)$ix[idx]

So you can use:

apply(gDistance(sp1, sp2, byid=TRUE), 1, f_which.min, idx = 1) 

Set the argument idx accordingly. That is, idx=1 first min, idx=2 second min and so on.

Upvotes: 1

Related Questions