返回两个数据帧中两个长纬度坐标的每行和每列之间的最小距离

Posted

技术标签:

【中文标题】返回两个数据帧中两个长纬度坐标的每行和每列之间的最小距离【英文标题】:Return minimum distance between each row and each column of two long lat coordinates in two dataframes 【发布时间】:2018-10-09 19:52:33 【问题描述】:

我想计算两个数据框的每行和列之间的最小地理距离。 DF1有很多机构,DF2有很多赛事。喜欢,所以:

#DF1 (institutions)
 DF1 <- data.frame(latitude=c(41.49532, 36.26906, 40.06599), 
 longitude=c(-98.77298, -101.40585, -80.72291))
 DF1$institution <- letters[seq( from = 1, to = nrow(DF1))] 

#DF2 (events)
 DF2 <- data.frame(latitude=c(32.05, 32.62, 30.23), longitude=c(-86.82,   
 -87.67, -88.02))
 DF2$ID <- seq_len(nrow(DF1)

我想将距离最小的事件返回到 DF1 中的每个机构,并将 DF2 到 DF1 的距离和 ID 添加。虽然我知道如何计算成对距离,但我无法计算从 DF[1,] 到 DF2 的所有距离并返回最小值等等。

这是我尝试过的(但失败了)。

  library(geosphere)

  #Define a function
   distanceCALC <- function(x, y)  distm(x = x, y = y, 
    fun = distHaversine)

  #Define vector of events 
   DF2_vec <- DF2[, c('longitude', 'latitude')]

  #Define df to hold distances
   shrtdist <- data.frame()

现在,我的尝试是向 distanceCALC 提供 DF1 的第 1 行和矢量化事件。

  #Loop through every row in DF1 and calculate all the distances to instutions a, b, c. Append to DF1 smallest distance + DF2$ID.

  #This only gives me the pairwise distance
   for (i in nrow(DF1))
    result  <- distanceCALC(DF1[i,c('longitude', 'latitude')], DF2_vec)
     
  #Somehow take shortest distance for each row*column distance matrix
   shrtdist <- rbind(shrtdist, min(result[,], na.rm = T))

我的猜测是,该解决方案需要对数据进行重塑和应用。此外,考虑到观察次数,循环是非常糟糕的做法,而且速度太慢。

非常感谢任何帮助。

【问题讨论】:

【参考方案1】:

这是一个使用outer 函数的简单方法

squared_distance <- function(x, y ) (x - y)^2

lat <- outer(DF1$latitude, DF2$latitude, squared_distance)
long <- outer(DF1$longitude, DF2$longitude, squared_distance)

pairwise_dist <- sqrt(lat + long)

rownames(pairwise_dist) <- DF1$institution
colnames(pairwise_dist) <- DF2$ID

pairwise_dist

这为您提供了每个机构(行)和事件(列)之间的距离矩阵。要获取df1中的距离和事件,我们可以这样做

df1$min_dist <- apply(pairwise_dist, 1, min)
df1$min_inst <- apply(pairwise_dist, 1, min)

请注意,第二个在这种情况下起作用的原因是因为事件是按数字标记的。如果您的真实数据没有那个方便的功能,我们需要这样做

df1$min_inst <- colnames(pairwise_dist)[apply(pairwise_dist, 1, which.min)]

使用替代距离函数更新

我没有对此进行测试,但我认为这应该可行。同样,输出将是一个矩阵。

gcd.hf <- function(DF1, DF2) 
  sin2.long <- sin(outer(DF1$longitude, DF2$longitude, "-") / 2)^2
  sin2.lat  <- outer(DF1$latitude, DF2$latitude, "-")
  cos.lat <- outer(cos(DF1$latitude), cos(DF2$latitude), "*")

  a <- sin2.long + sin2.lat * cos.lat # we do this cell-wise
  cir <- 2 * asin(pmin(1, sqrt(a))) # I never assign anything to "c" since that's concatenate.  Rename this variable as appropriate (I have no idea if it's related to the circumference or not.)
  cir * 6371


pairwise_dist <- gcd.hf(DF1, DF2)

【讨论】:

非常感谢。这看起来整洁而优雅。只是快速跟进。以前我用 Haversine 函数计算了距离。但是,在您的解决方案中,您只需取平方距离。我不是地理数据专家,但你的计算对应的是什么?例如。 distm(x=c(-98.77298,41.49532), y=c(-86.82, 32.05),fun = distHaversine)/1000 产生 1494.378 km 而您的方法产生 15.23443。这对应什么? 另外,仅供参考。最后一行产生'NA'。它适用于DF1$min_inst &lt;- colnames(pairwise_dist)[apply(pairwise_dist, 1, which.min)] 是的,which.min 是正确的 - 我修复了它。至于距离,有很多距离函数。我不熟悉 Haversine 函数(当我第一次查看您的代码时错过了那个细节),所以我只是坚持使用默认值(欧几里得)。但是,它最终不是平方距离,因为当我将纬度和经度的平方距离结合起来时,我确实取了平方根。希望您可以使用您实际需要的距离函数来实现类似的功能(如果您遇到问题,我会看看是否可以)。 谢谢。实际上,我仍然无法将您的解决方案应用于我的公式。您正在使用两个数据帧的纬度和经度计算距离矩阵。但是,我正在使用的函数是以下gcd.hf &lt;- function(long1, lat1, long2, lat2) R &lt;- 6371 # Earth mean radius [km] delta.long &lt;- (long2 - long1) delta.lat &lt;- (lat2 - lat1) a &lt;- sin(delta.lat/2)^2 + cos(lat1) * cos(lat2) * sin(delta.long/2)^2 c &lt;- 2 * asin(min(1,sqrt(a))) d = R * c return(d) # Distance in km 您能否给我提示一下在这种情况下如何应用外部函数?

以上是关于返回两个数据帧中两个长纬度坐标的每行和每列之间的最小距离的主要内容,如果未能解决你的问题,请参考以下文章

尝试根据每个数据帧中的经纬度差异比较两个数据帧

如何在不同的数据帧中选择特定时间段内的点,然后根据纬度/经度选择这两个点之间的距离

C# 在 Linq 查询 WHERE 语句中返回两个纬度/经度坐标之间的计算距离

用 1 和 -1 填充 n x n 零矩阵的方法,使得每行和每列只能有一个 1 和 -1,并且每行和每列的总和为 0

R - 数据帧中的条件更新坐标列

Java求解! 定义一个6行6列的二维整型数组,输出该二维数组中的每行和每列的最大值、最小值、和平均值。