【问题标题】:Distances of points between rows with sf带 sf 的行与点之间的距离
【发布时间】:2018-09-25 23:30:57
【问题描述】:

我有多个轨迹保存在 POINT 类型的简单特征 (sf) 中。我想计算后续位置(即行)之间的欧几里得距离。到目前为止,我已经使用Pythagorean formula for calculating Euclidean Distances in 2D space“手动”计算了距离。我想知道是否可以使用函数sf::st_distance() 来做同样的事情。这是一个简单的例子:

library(sf)
library(dplyr)

set.seed(1)

df <- data.frame(
  gr = c(rep("a",5),rep("b",5)),
  x  = rnorm(10),
  y = rnorm(10)
 )

df <- st_as_sf(df,coords = c("x","y"),remove = F)


df %>%
  group_by(gr) %>%
  mutate(
    dist = sqrt((lead(x)-x)^2+(lead(y)-y)^2)
  )
#> Simple feature collection with 10 features and 4 fields
#> geometry type:  POINT
#> dimension:      XY
#> bbox:           xmin: -0.8356286 ymin: -2.2147 xmax: 1.595281 ymax: 1.511781
#> epsg (SRID):    NA
#> proj4string:    NA
#> # A tibble: 10 x 5
#> # Groups:   gr [2]
#>    gr         x       y   dist                 geometry
#>    <fct>  <dbl>   <dbl>  <dbl>                  <POINT>
#>  1 a     -0.626  1.51    1.38     (-0.6264538 1.511781)
#>  2 a      0.184  0.390   1.44     (0.1836433 0.3898432)
#>  3 a     -0.836 -0.621   2.91   (-0.8356286 -0.6212406)
#>  4 a      1.60  -2.21    3.57        (1.595281 -2.2147)
#>  5 a      0.330  1.12   NA         (0.3295078 1.124931)
#>  6 b     -0.820 -0.0449  1.31  (-0.8204684 -0.04493361)
#>  7 b      0.487 -0.0162  0.992  (0.4874291 -0.01619026)
#>  8 b      0.738  0.944   0.204    (0.7383247 0.9438362)
#>  9 b      0.576  0.821   0.910    (0.5757814 0.8212212)
#> 10 b     -0.305  0.594  NA       (-0.3053884 0.5939013)

我想用sf::st_distance() 计算dist。我该怎么办?

【问题讨论】:

    标签: r dplyr sf


    【解决方案1】:

    首先要了解sf 是几何列(sfc 类中的一个)作为列表列存储在数据框中。 通常对列表列做任何事情的关键是要么使用purrr::map 和朋友,要么使用接受列表列作为参数的函数。对于st_distance,它的参数可以是sf(数据框)、sfc(几何列)甚至sfg(单个几何行)的对象,所以不需要@ 987654328@和朋友。解决方案应如下所示:

    df %>%
      group_by(gr) %>%
      mutate(
        dist = st_distance(geometry)
      )
    

    但是,这不起作用。经过一番调查,我们发现了两个问题。首先,st_distance 返回一个距离矩阵而不是单个值。为了解决这个问题,我们使用了st_distanceby_element = T 参数。

    接下来,我们不能只使用dist = st_distance(geometry, lead(geometry), by_element = T),因为lead 仅适用于向量列,而不适用于列表列。

    为了解决第二个问题,我们使用geometry[row_number() + 1] 自己创建了前导列。

    这是完整的解决方案:

    library(sf)
    library(dplyr)
    
    df %>%
      group_by(gr) %>%
      mutate(
        lead = geometry[row_number() + 1],
        dist = st_distance(geometry, lead, by_element = T),
      )
    #> Simple feature collection with 10 features and 4 fields
    #> Active geometry column: geometry
    #> geometry type:  POINT
    #> dimension:      XY
    #> bbox:           xmin: -0.8356286 ymin: -2.2147 xmax: 1.595281 ymax: 1.511781
    #> epsg (SRID):    4326
    #> proj4string:    +proj=longlat +datum=WGS84 +no_defs
    #> # A tibble: 10 x 6
    #> # Groups:   gr [2]
    #>    gr         x       y  dist                       geometry
    #>    <fct>  <dbl>   <dbl> <dbl>         <sf_geometry [degree]>
    #>  1 a     -0.626  1.51   1.38     POINT (-0.6264538 1.511781)
    #>  2 a      0.184  0.390  1.44     POINT (0.1836433 0.3898432)
    #>  3 a     -0.836 -0.621  2.91   POINT (-0.8356286 -0.6212406)
    #>  4 a      1.60  -2.21   3.57        POINT (1.595281 -2.2147)
    #>  5 a      0.330  1.12   0         POINT (0.3295078 1.124931)
    #>  6 b     -0.820 -0.0449 1.31  POINT (-0.8204684 -0.04493361)
    #>  7 b      0.487 -0.0162 0.992  POINT (0.4874291 -0.01619026)
    #>  8 b      0.738  0.944  0.204    POINT (0.7383247 0.9438362)
    #>  9 b      0.576  0.821  0.910    POINT (0.5757814 0.8212212)
    #> 10 b     -0.305  0.594  0       POINT (-0.3053884 0.5939013)
    #> # ... with 1 more variable: lead <sf_geometry [degree]>
    

    【讨论】:

    • 感谢您不仅分享您的解决方案,还感谢您的想法。让这个答案变得无价!