【问题标题】:Alter a column based on results from geodistance matrix根据地理距离矩阵的结果更改列
【发布时间】:2021-03-27 14:19:48
【问题描述】:

我有一个如下所示的数据框:

long       lat       site
-141.37    61.13     x1
-149.1833  66.7333   x2
-149.667   67.667    x3
-141.3667  61.1157   x4

我想使用distVincentyEllipsoid 计算所有site 之间的距离。然后对于彼此相距 5 公里以内的那些站点,我想修改 site 名称以包含两个站点。所以,在这个例子中,x1x4 相距在 5 公里以内,所以会是这样的:

 long      lat       site  
-141.37    61.13     x1_x4    
-149.1833  66.7333   x2
-149.667   67.667    x3
-141.3667  61.1157   x1_x4

我知道我可以通过这种方式计算所有site 之间的矩阵:

df %>% dplyr::select('long', 'lat')
distm(df, fun = distVincentyEllipsoid)

但我不知道如何从那里得到它。

【问题讨论】:

    标签: r geosphere


    【解决方案1】:

    如果您以 R 代码的形式提供示例数据会很有帮助,就像这样

    x <- matrix(c(-141.37, 61.13, -149.1833, 66.7333, -149.667, 67.667, -141.3667, 61.1157), ncol=2, byrow=TRUE)
    colnames(x) <- c("lon", "lat")
    x <- data.frame(site=paste0("x", 1:4), x)
    

    但感谢您显示预期的输出

    解决方案:

    按照您的建议,首先制作一个距离矩阵。然后将其分类为是否在阈值距离内,然后使用行来选择记录。请注意,我使用distGeo --- 这是比distVincentyEllipsoid 更好的方法。

    library(geosphere)
    m <- distm(x[, c("lon", "lat")], fun=distGeo)
    
    m <- m < 5000
    x$name <- apply(m, 1, function(i) paste(x$site[i], collapse="_"))
    x
    #  site       lon     lat    name
    #1   x1 -141.3700 61.1300   x1_x4
    #2   x2 -149.1833 66.7333      x2
    #3   x3 -149.6670 67.6670      x3
    #4   x4 -141.3667 61.1157   x1_x4
    

    如果您有很多点,距离矩阵可能会变得太大。在这种情况下,你可以这样做

    y <- x[,  c("lon", "lat")]
    for (i in 1:nrow(y)) {
       j <- distGeo(y[i, ], y) < 5000
       x$name[i] <- paste(x$site[j], collapse="_")
    } 
    

    或者像这样

    y <- x[,  c("lon", "lat")]
    x$name <- x$site    
    for (i in 1:nrow(y)) {
       j <- distGeo(y[i, ], y) < 5000
       if (any(j)) {
           x$name[i] <- paste(x$site[j], collapse="_")
       }
    } 
    

    【讨论】:

      【解决方案2】:

      这是一个使用tidyverse的答案:

      library(geosphere)
      
      dist_mat <- distm(select(df, long, lat), fun = distVincentyEllipsoid)
      
      
      df %>%
        mutate(site_new = map_chr(1:n(), ~paste0(df$site[which(dist_mat[,.x] <= 5000)], collapse = "_")))
      
      
      # A tibble: 4 x 4
         long   lat site  site_new
        <dbl> <dbl> <chr> <chr>   
      1 -141.  61.1 x1    x1_x4   
      2 -149.  66.7 x2    x2      
      3 -150.  67.7 x3    x3      
      4 -141.  61.1 x4    x1_x4  
      

      【讨论】:

        最近更新 更多