R:计算从一个点到另一个点的距离(以英里为单位)

时间:2018-08-13 14:12:37

标签: r dplyr geospatial geosphere

我有以下数据帧:

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中标题之间的距离(以英里为单位)。因此,在d2中,tas1的坐标为54.6 lat,长度为1.2,在'Base'列中具有'base1'。所以我想计算54.6lat x 1.2long和57.3lat与0.4lon之间的距离。

我尝试使用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 个答案:

答案 0 :(得分:5)

这可以使用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)

答案 1 :(得分: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

答案 2 :(得分: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)

答案 3 :(得分: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 package(v0.2.0)于2018-08-13创建。