交叉两组坐标以计算最小距离? (tidyr geosphere R)

Crossing two sets of coordinates in order to calculate minimum distance? (tidyr geosphere R)

我在同一边界区域中有一组 2,220 个巢坐标 (var1) 和另一组 26 个地标坐标 (var2)。我想找到 2,224 个坐标中的每一个与 26 个坐标中的每个点之间的距离,以便创建一个包含列的新数据框(巢坐标、最小距离地标坐标、以米为单位的距离)。

我一直在尝试交叉这两个集合以生成一个集合,其中所有地标坐标都与每个嵌套坐标配对。

**nest**                **landmark**         **distance**

lat1, lon1              lat1, lon1            34
lat1, lon1              lat2, lon2            18
lat1, lon1              lat3, lon3            82
....
lat1, lon1              lat26,lon26           61
lat2, lon2              lat1, lon1            94
lat2, lon2              lat2, lon2            38
...
lat2,220, lon 2,220     lat 26,lon26          46

我尝试过 crossing(var1, var2),其中 var1 和 var2 都是包含纬度和经度值的矩阵,然后计算每个结果行之间的 Haversine 距离(见下文)。这似乎行得通,但我认为它并没有给我预期的确切结果。交叉得到的行数与这些集合的 nrow 的乘积不一致。

我还希望能够将具有所有距离值的结果集分成 26 组,其中每组包含嵌套坐标(对每一行重复)、26 个地标坐标之一和距离两点之间。从那里,我将 select 用于最小距离的行。

newset <- crossing(nests, landmarks)
mindist <- distHaversine(newset[1], newset[2], r=6378137)
newsetwdist <- cbind(newset, mindist)

sv <- split(newsetwdist,rep(1:56056,each=26))
#56056 was the resulting number of rows, even though I expected 57,720.

var3 <- lapply(sv, "[", 3) #returns a nested list of all distances for each nest
var4 <- lapply(var2, "[[", "mindist")

df = as.data.frame(do.call(rbind, lapply(var4, unlist)))
min.dist.from.landmark <- apply(df, 1, FUN=min)

看来这应该是一个简单的修复,我们将不胜感激。

使用我为此制作的数据和数据格式,您可以执行以下操作。

library(dplyr)
library(purrr)
library(tidyr)
library(geosphere)

crossing(nest, landmark) %>%
  mutate(nest_long_lat = map2(nest_long, nest_lat, ~ c(.x, .y)),
         mark_long_lat = map2(mark_long, mark_lat, ~ c(.x, .y)),
         distance = unlist(map2(mark_long_lat, nest_long_lat, ~ distGeo(.x, .y)))) %>%
  group_by(nest_long_lat) %>%
  mutate(min_distance = distance == min(distance)) %>%
  ungroup() %>%
  select(-nest_long_lat, -mark_long_lat)

# # A tibble: 57,720 x 6
#          nest_lat nest_long mark_lat mark_long distance min_distance
#          <dbl>    <dbl>     <dbl>    <dbl>     <dbl>    <lgl>       
# 1        46.5      49.1     48.4      49.8     215350.  TRUE        
# 2        46.5      49.1     48.6      48.7     229592.  FALSE       
# 3        46.5      49.1     48.8      49.9     255689.  FALSE       
# 4        46.5      49.1     48.9      48.4     268789.  FALSE       
# 5        46.5      49.1     49.3      50.1     312691.  FALSE       
# 6        46.5      49.1     49.3      49.2     309549.  FALSE       
# 7        46.5      49.1     49.6      51.6     390862.  FALSE       
# 8        46.5      49.1     49.7      50.8     371686.  FALSE       
# 9        46.5      49.1     49.8      50.6     377182.  FALSE       
# 10       46.5      49.1     49.9      49.9     376530.  FALSE       
# # … with 57,710 more rows

数据

nest <- tibble(nest_lat = rnorm(50, n = 2220),
               nest_long = rnorm(50, n = 2220))

landmark <- tibble(mark_lat = rnorm(50, n = 26),
                   mark_long = rnorm(50, n = 26))