R: 从一个点到另一个点的英里距离计算

5

我有以下数据框:

library(dplyr)

d1 <- data_frame(
title = c("base1", "base2", "base3", "base4"),
lat = c(57.3, 58.8, 47.2, 57.8),
long = c(0.4, 3.4, 3.5, 1.2))

d2 <- data_frame(
tas = c("tas1", "tas2", "tas3", "tas4"),
Base= c ("base1", "base2", "base3", "base4"),
lat=c(54.6, 56.4, 54.2, 54.6),
long = c(1.2, 3.4, 3.5, 56.6))

我想做的是计算d2中tas和d1中title之间的英里距离。所以在d2中,tas1具有54.6纬度和1.2经度的坐标,并在“Base”列中具有“base1”。因此,我想计算54.6纬度和1.2经度与57.3纬度和0.4经度之间的距离。
我尝试使用下面详细说明的GeoDistanceInMetresMatrix函数来实现这一点,但该函数并没有给出我想要的结构。
下面的文章提供了有关GeoDistanceInMetresMatrix的一些信息。

http://eurekastatistics.com/calculating-a-distance-matrix-for-geographic-points-using-r/

这就是我想要数据看起来的样子:

 df <- data_frame(
tas = c("tas1", "tas2", "tas3", "tas4"),
Base= c ("base1", "base2", "base3", "base4"),
lat=c(54.6, 56.4, 54.2, 54.6),
long = c(1.2, 3.4, 3.5, 56.6),
difference_miles = c(23, 35, 56, 23))

我整个下午都在看这个,但无法完全弄对,希望能得到任何帮助!

4个回答

6
这可以很容易地通过使用geosphere库来实现:
d1 <- data.frame(
  title = c("base1", "base2", "base3", "base4"),
  lat = c(57.3, 58.8, 47.2, 57.8),
  long = c(0.4, 3.4, 3.5, 1.2))

d2 <- data.frame(
  tas = c("tas1", "tas2", "tas3", "tas4"),
  Base= c ("base1", "base2", "base3", "base4"),
  lat=c(54.6, 56.4, 54.2, 54.6),
  long = c(1.2, 3.4, 3.5, 56.6))

library(geosphere)
#1609.35 is the conversion from miles to meters
dist<-distGeo(d1[, c("long", "lat")], d2[, c("long", "lat")])/1609.35
df<-cbind(d2, difference_miles=dist)

非常感谢,这正是我所需要的。我想我可能过于复杂化了GeoDistanceInMetresMatrix。 - Mrmoleje
如果d2看起来像这样 d2 <- data.frame(tas =c("tas1", "tas2", "tas3", "tas4"), Base= c ("base1", "base2", "base1", "base2"), lat=c(54.6, 56.4, 54.2, 54.6), long = c(1.2, 3.4, 3.5, 56.6)) - Mrmoleje
我不完全理解你的后续问题。distGeo函数计算两个坐标对之间的距离。只要坐标向量长度相同或彼此是偶数倍,它仍然可以工作。如果d1和d2之间没有一对一的关系,则考虑将所有数据合并到一个大型数据框中进行计算。请参见丹的答案以了解如何执行此操作。 - Dave2e
好的,我现在明白了。如果我连接这两个数据框,那么它只适用于我的特定示例,但我现在意识到了。感谢您的帮助。 - Mrmoleje

5

一种方法是使用 geosphere 包:

# slightly modify your data because I want to merge it
df1 <- data.frame(
    title = c("base1", "base2", "base3", "base4"),
    lat1  = c(57.3, 58.8, 47.2, 57.8),
    long1 = c(0.4, 3.4, 3.5, 1.2), 
    stringsAsFactors = FALSE)

df2 <- data.frame(
    title = c ("base1", "base2", "base3", "base4"),
    lat2  = c(54.6, 56.4, 54.2, 54.6),
    long2 = c(1.2, 3.4, 3.5, 56.6), 
    stringsAsFactors = FALSE)

# merge your data so you're sure your lat/long pairs make sense
df <- merge(df1, df2, by="title")

# calculate distance according to the Haversine method (shortest dist around sphere)
df$dist_meters <- geosphere::distHaversine(
    p1=df[ , c("long1", "lat1")],
    p2=df[ , c("long2", "lat2")]  )

# convert meters to miles
df$dist_miles = df$dist_meters / 1609.34

好的,谢谢。这很有道理。如果在df2中标题发生变化怎么办?例如,如果它看起来像 d2 <- data.frame(title =c("base1", "base2", "base1", "base2"), lat=c(54.6, 56.4, 54.2, 54.6), long = c(1.2, 3.4, 3.5, 56.6)) - Mrmoleje
我的意思只是将经纬度放在数据框的同一行中(而不是放在不同的数据框中)更“安全”,这样你就可以确保正确地将“起点”经纬度与“终点”经纬度匹配。我更改了你的数据,以便在计算距离之前可以进行合并,但你应该根据自己的情况调整我的代码,使其符合你的需求。 - DanY
好的,我现在明白了,并且已经成功地处理了我的数据。谢谢! - Mrmoleje

2

您还应该查看sp

library(sp)
p1 <- SpatialPoints(select(d1, long, lat))
p2 <- SpatialPoints(select(d2, long, lat))
spDists(p1, p2, longlat=TRUE, diagonal=TRUE)
# [1]  304.7427  267.2908  778.7028 3359.7988    (output is km)

这个好像不太行。我收到了错误信息 警告信息: 在 spDists(p1, p2, longlat = TRUE, diagonal = TRUE) 中: spDists: 参数 longlat 与 CRS(x) 冲突;使用值 TRUE - Mrmoleje
错误和警告是不同的 - 一旦转换为英里,它们的值接近于geosphere提供的值。 - CPak

1

由于您已经在使用dplyr,因此您可以轻松地将sf添加到您的工作流程中。在这里,我使用经度/纬度坐标和经度/纬度投影将两个数据框转换为具有sf列的数据框。然后,我将它们各自转换为基于美国英尺的投影,并获取距离。如果需要,您可以将该距离向量添加到两个初始数据框的联接版本中。

需要注意的一点是顺序-我按照基本标签排列了d1_sfd2_sf,但如果在更大或更复杂的数据集中不起作用,或者存在缺失的基地,则可以在此处使用联接进行检查。

library(tidyverse)
library(sf)

...

d1_sf <- st_as_sf(d1, coords = c("long", "lat"), crs = 4326) %>%
  arrange(title)
d2_sf <- st_as_sf(d2, coords = c("long", "lat"), crs = 4326) %>%
  arrange(Base)

distances <- st_distance(
  st_transform(d1_sf, crs = 2234),
  st_transform(d2_sf, crs = 2234),
  by_element = T
)

distances
#> Units: US_survey_foot
#> [1]  1035387.8   916425.4  2591457.0 11553291.3

inner_join(d1, d2, by = c("title" = "Base"), suffix = c("1", "2")) %>%
  mutate(dist = distances) %>%
  mutate(dist_mi = dist / 5280)
#> # A tibble: 4 x 8
#>   title  lat1 long1 tas    lat2 long2 dist               dist_mi          
#>   <chr> <dbl> <dbl> <chr> <dbl> <dbl> <S3: units>        <S3: units>      
#> 1 base1  57.3   0.4 tas1   54.6   1.2 " 1035387.8 US_su… " 196.0962 US_su…
#> 2 base2  58.8   3.4 tas2   56.4   3.4 "  916425.4 US_su… " 173.5654 US_su…
#> 3 base3  47.2   3.5 tas3   54.2   3.5 " 2591457.0 US_su… " 490.8062 US_su…
#> 4 base4  57.8   1.2 tas4   54.6  56.6 11553291.3 US_sur… 2188.1234 US_sur…

这段内容是由reprex包(v0.2.0)于2018年8月13日创建的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接