Как получить расстояние и идентификатор ближайшей точки в одном пространственном фрейме данных до каждой точки в другом пространственном фрейме данных - PullRequest
0 голосов
/ 19 декабря 2018

У меня есть два фрейма данных, set1 и set2, оба с длинными координатами.Я хочу

1) найти ближайшую точку в set2 для каждой точки в set1 2) записать расстояние и добавить его в столбец в set1 3) получить идентификатор и добавить его в столбец в set1

Я написал следующий код, но он очень медленный для моего полного набора данных (50 000 точек в set1 и 1000 в set2).

Этот код работает, но он медленный.Возможно я могу преобразовать это в заявление о применении?Проблема в том, что я не знаю как.

Спасибо

## load in library
library(spdep)
library(sp)
library(geosphere)

## create some fake data and convert them to spatial objects
set1<- data.frame(cbind(runif(25000,-10.8544921875,2.021484375),runif(40,49.82380908513249,59.478568831926395)))
names(set1)<-c("lon","lat")
coordinates(set1)<-~lon+lat


set2<-data.frame(cbind(runif(1000,-10.8544921875,2.021484375),runif(40,49.82380908513249,59.478568831926395)))
names(set2)<-c("lon","lat")
coordinates(set2)<-~lon+lat
set2$ID<-seq(1:dim(data.frame(set2))[1])

plot(set1, col="blue", pch=16)
plot(set2, col="grey", pch=16, add=TRUE)

##Calculate distances from points in set1 to points in set2
dists.set1.set2<-distm (set1, set2,fun = distHaversine)/1609

## create a variable for the distance from every point in set1 to the nearest point in set2
set1$distance.to.nearest.point<-apply(dists.set1.set2,1,min)


## Get the id of the point in set2 closest to each point in set1    
for (i in 1:dim(set1)[1]){          


 if(length(which(dists.set1.set2[i,]==set1$distance.to.nearest.point[i]))>0){           
set1$closest.point.in.set2[i]<-set2$ID[which(dists.set1.set2[i,]==set1$distance.to.nearest.point[i])]           
  }         
} 

1 Ответ

0 голосов
/ 07 января 2019

дайте мне знать, если следующее соответствует вашим потребностям.

В приведенном вами примере dists.set1.set2 - это матрица расстояний из 25 000 строк (для set1) и 1000 столбцов (set2).Чтобы получить ID ближайших точек от set2 до set1, вы упорядочите расстояния в каждой строке и возьмете первый столбец, используя функцию order().Это представляет индекс строки в set2, которая соответствует кратчайшему расстоянию между set2 и конкретной точкой в ​​set1.

Ниже приведен код для переноса этогои выполните несколько логических тестов, чтобы убедиться, что мы действительно берем точку из set2, ближайшую к set1.

Пример:

# Obtain ORDER of position of set1 in increasing distance -- note that R transposed the matrix, hence the need for `t`
dist_order = dists.set1.set2 %>% apply(MARGIN = 1, FUN = order) %>% t

# Verify that the order is increasing. Top row is the closest distance.
dist_sorted = dists.set1.set2 %>% apply(MARGIN = 1, FUN = sort) %>% t

index_shortest_dist = dist_order[,1]

# Make set1 spdf and add data frame columns for the closest set2 ID and the closest distance.
set1 = sp::SpatialPointsDataFrame(coords = set1, data = data.frame(ClosestID = rep(NA, NROW(set1)),
                                                                   ClosestDist = rep(NA, NROW(set1))))

# Pull the proper data from set2. Use pull to obtain a vector instead of a df.
set1@data$ClosestID = set2 %>% data.frame %>% slice(index_shortest_dist) %>% pull(ID)

# Pull the proper data from the sorted distance list.
set1@data$ClosestDist = dist_sorted[,1]

# Verify a few test cases

# Random row position
rand = sample(seq(1, NROW(set1)), size = 1)

# Take the ID generated previously from from corresponding row in set1
closest_ID = set1[rand,]$ClosestID

# Take the corresponding point from set2 using the ID obtained from the previous operation
set2_closest_candidate = set2[which(closest_ID == set2$ID),]

# What's the difference in distance between the set2 candidate and the point in set1, and is it equal to the minimum distance between that point in set1 and all the points in set2?
# Will return TRUE if the closest point is correctly idenfied.
dist_to_candidate = distm(set1[rand,], set2_closest_candidate, fun = distHaversine)/1609

min_dist_to_set2  = (distm(set1[rand,], set2, fun = distHaversine)/1609) %>% min

set2_id_min_dist  = set2$ID[which.min(distm(set1[rand,], set2, fun = distHaversine)/1609)]

# Tests
dist_to_candidate == min_dist_to_set2
set1[rand,]$ClosestID == set2_id_min_dist


# Is the distance obtained correctly? Should match `(distm(set1[rand,], set2, fun = distHaversine)/1609) %>% min`
set1@data$ClosestDist[rand] == (distm(set1[rand,], set2, fun = distHaversine)/1609) %>% min
...