I noticed the nngeo package some days ago and think the functionality might be handy here:
library(sf) library(nngeo) # create a sf object from your data frame sf <- st_as_sf(df, coords = c("LAT", "LONG"), crs = 4326) # filter by year sf_sub <- dplyr::filter(sf, HD_YEAR == "2019") # perform nearest neighbor search for simple features res <- st_nn(sf_sub, sf_sub, k = 3+1) # perform nearest neighbor search for simple features result <- st_nn(sf_sub, sf_sub, k = 3+1, returnDist = TRUE) nn <- result[["nn"]] dist <- result[["dist"]] # remove distance to self nn <- lapply(nn, tail, -1) nn #> [[1]] #> [1] 5 3 2 #> #> [[2]] #> [1] 3 4 5 #> #> [[3]] #> [1] 2 5 4 #> #> [[4]] #> [1] 2 3 5 #> #> [[5]] #> [1] 3 2 4 dist <- lapply(dist, tail, -1) dist #> [[1]] #> [1] 3763.359 4626.834 4832.484 #> #> [[2]] #> [1] 213.6749 678.6742 1070.9202 #> #> [[3]] #> [1] 213.6749 870.6891 885.9632 #> #> [[4]] #> [1] 678.6742 885.9632 1749.2748 #> #> [[5]] #> [1] 870.6891 1070.9202 1749.2748 # use indices to query your nest ids sf_sub$NEST_NUMBER[nn[[1]]] #> [1] "LOSH-2020-06" "LOSH-2019-03" "LOSH-2019-02" Interpretation: The nearest nests to nest 1 are nests 5, 3, 2; nearest ones to nest 2 are nests 3, 4, 5, and so on. I would try to apply this snippet on your complete dataset to be sure if it works properly.