【问题标题】:R: Calculating distance in miles from one point to anotherR:计算从一点到另一点的距离(以英里为单位)
【发布时间】:2018-08-13 23:11:37
【问题描述】:

我有以下数据框:

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 long,并且在“Base”列中有“base1”。所以我想计算54.6lat乘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))

我整个下午都在看这个,但不能完全正确,所以任何帮助都将不胜感激!

【问题讨论】:

    标签: r dplyr geospatial geosphere


    【解决方案1】:

    使用 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 过于复杂了
    • 如果 d2 看起来像这样d2 &lt;- 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))
    • 我不完全理解您的后续问题。 distGeo 函数计算 2 对坐标之间的距离。只要坐标的向量长度相同或互为偶数倍,它仍然可以工作。如果 d1 和 d2 之间没有 1 对 1 的关系,则考虑将所有数据合并到 1 个大数据帧中来执行计算。有关执行此操作的方法,请参阅 Dan 的答案。
    • 好的,我现在明白了。如果我加入两个数据框,这仅适用于我的具体示例,但我现在意识到了这一点。感谢您的帮助
    【解决方案2】:

    一种方法可能是使用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 &lt;- 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)).
    • 我的意思是,将 lat/lng 都放在数据帧的一行中(而不是将它们放在不同的数据帧中)“更安全”,这样您就确定 您正确匹配“从”纬度/经度到“到”经度/经度。我更改了您的数据,以便在计算距离之前可以完成合并,但是您应该根据需要调整我的代码,以便在您的情况下有意义。
    • 好的,我现在明白了,并设法用我的数据解决了这个问题。谢谢!
    【解决方案3】:

    您还应该查看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)
    

    【讨论】:

    • 这不太行。我收到错误消息Warning message: In spDists(p1, p2, longlat = TRUE, diagonal = TRUE) : spDists: argument longlat conflicts with CRS(x); using the value TRUE
    • 错误和警告是不同的 - 转换为英里后,这些值与 geosphere 提供的值接近
    【解决方案4】:

    由于您已经在使用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 年 8 月 13 日创建。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-10
      • 2011-02-07
      • 2011-09-10
      • 2016-05-13
      • 1970-01-01
      相关资源
      最近更新 更多