Reputation: 55
I have a dataframe that has a list of places and their geographical locations in UTM (Universal Transverse Mercator) coordinates.
It looks something like this:
Place X_UTM Y_UTM
1 574262.0 6140492
2 571251.2 6141669
3 570841.9 6142535
4 570233.8 6141213
5 578269.2 6140304
6 575067.1 6137444
I want to identify, for each Place (each row of the dataframe), which of the other places are within a given Euclidean distance. In this case, I want to find which places are closer than 1 kilometer.
I've tried something like this:
foo <- function(x, y) dist(c(x, y), method = "euclidian") < 1000
which should be a function that returns the points that are closer than 1000 meters. Then:
x <- lapply(df(,c(i, x, y)), FUN = foo)
where i
is "Place"
, x
is "X_UTM"
and y
is "Y_UTM"
. This do not work at all.
The output I am after should look something like this (not obtained from the numbers given above):
# Place Closest
# 1 2, 5
# 2 1
# 3 NA
# 4 5
# 5 1, 4
# 6 NA
Upvotes: 2
Views: 1261
Reputation: 27388
You can also use sp::spDists
to return a distance matrix, and then find the elements of each column/row that meet your condition.
For example:
d <- read.table(text='Place X_UTM Y_UTM
1 574261.98 6140492.13
2 571251.23 6141669.26
3 570841.92 6142534.86
4 570233.75 6141212.5
5 578269.25 6140303.78
6 575067.07 6137444.36', header=TRUE)
library(sp)
i <- apply(spDists(as.matrix(d[, c('X_UTM', 'Y_UTM')])), 2,
function(x) paste(which(x < 1000 & x != 0), collapse=', '))
data.frame(Place=d$Place, Closest=i)
## Place Closest
## 1 1
## 2 2 3
## 3 3 2
## 4 4
## 5 5
## 6 6
Upvotes: 2
Reputation: 520878
I think you are going to need to cross join the Place coordinates. The reason for this is that any pair of Places could be nearest neighbors, and assuming you don't have any a priori information which could rule out certain pairs, you need to check all of them.
One way of getting the cross join of your data frame df
is to merge it with itself, setting by = NULL
as a parameter into merge
:
df.cross <- merge(x = df, y = df, by = NULL)
df.cross$distance <- apply(df.cross[, c('X_UTM.x', 'X_UTM.y', 'Y_UTM.x', 'Y_UTM.y')],
1,
function(x) dist(x[1], x[2], x[3], x[4]))
Now all you need to do is find the minimum distance for each pair of places.
Upvotes: 0