【问题标题】:Write an efficient loop to compare gps coordinates编写一个高效的循环来比较gps坐标
【发布时间】:2020-07-22 22:38:44
【问题描述】:

我想通过 GPS 坐标的数据框并删除所有彼此靠近的坐标。

pick first row
  clalulate the distance between selected and the next row
  if the distance is < mindist and current row is not the last row continue to next row
  else select the current row (leave it in dataframe) and if the selected row is not the last row
   repeat from the begining

结果应该是一个数据帧,其 gps 点至少彼此相距mindist

一种方法是:

 node_distances <- function(node_coords)
  {
  n <- nrow(node_coords)
  from <- 1:(n - 1)
  to <- 2:n
  return(c(0, geodist::geodist_vec(node_coords[from, ]$lon,node_coords[from, ]$lat, node_coords[to, ]$lon, node_coords[to, ]$lat, paired = TRUE, measure = "geodesic")))
}
distances %>% filter(dist < mindist)

但是这种方法只测试 2 行,这意味着它会在文件中产生很大的空白。

我开始编写嵌套循环,但他的决定很糟糕,不起作用而且速度很慢:

node_distances_hack <- function(node_coords)
{
  n <- nrow(node_coords)
  for(i in 1:n) {
    print(node_coords[i,])
    a<-i
    distance_c<-0
    mindist<-50
    while(distance_c<mindist || a >= n){
      distance_c<-geodist::geodist_vec(node_coords[i,]$lat,node_coords[i,]$lon,node_coords[a,]$lat,node_coords[a,]$lon, paired = TRUE, measure = "cheap")
      a<-a+1
      }
  }
}

什么是更好的方法? 先感谢您, BR

【问题讨论】:

  • 这可能最好使用fuzzyjoin::geo_join 来实现。此函数可以根据位置之间的距离连接两个数据帧。这个函数像标准的 dplyr 连接操作一样工作,除了你需要指定点之间的最小距离等。
  • 嗨罗伯特,感谢您的回复:它如何在单个数据帧上工作?
  • 您可以以此为起点:tibble::tibble(longitude = c(0, 0,0,10, 10.1), latitude = c(0, 0.1, 10, 10, 10)) %&gt;% fuzzyjoin::geo_left_join(df, max_dist = 10, unit = "km")。这将连接两个数据框,将其限制为相距不到 10 公里的坐标
  • @Robert 我在 UseMethod("tbl_vars") 中发现了一个错误 Fehler:nicht anwendbare Methode für 'tbl_vars' auf Objekt der Klasse "function" angewendet。如果我翻译正确,tibble (tbl_vars) 中的方法不能使用?

标签: r dplyr tidyr


【解决方案1】:

您可以通过使用geodist:::geodist_xy_vec 来获取每对点之间的距离,从而完全不用循环来执行此操作,因为这会生成一个成对矩阵。考虑这个函数:

remove_close <- function(df, CLOSE = 10000)
{
  dist_mat <- geodist:::geodist_xy_vec(df$lon, df$lat, df$lon, df$lat, "cheap")
  diag(dist_mat) <- CLOSE + 1
  clashes <- which(dist_mat < CLOSE, arr.ind = TRUE)
  duplicates <- unique(t(apply(clashes, 1, sort)))[, 2]
  df[-duplicates, ]
}

library(ggplot2)

set.seed(69)

df <- data.frame(lat  = runif(1000, 51, 54),
                 lon = runif(1000, 8, 13))

ggplot(df, aes(lon, lat)) + geom_point()


ggplot(remove_close(df), aes(lon, lat)) + geom_point()

reprex package (v0.3.0) 于 2020 年 7 月 22 日创建

【讨论】:

  • 谢谢艾伦,它正在工作,我需要进一步查看数据,但它似乎工作。当 CLOSE = 0.001 时,它会将数据帧从 1481 行减少到 77 行。这个 rad 测量值是多少?
  • @Andreas 这是问题所在。它以度为单位,就像纬度和经度一样。这意味着绝对距离将根据纬度略有变化。如果需要,可以使用geodist 函数重写它以提供准确的距离。
  • 好的,艾伦,我需要理解函数 OUTER 来重写它。非常感谢您迄今为止的努力!
  • @Andreas 实际上,我已经意识到 geodist 包含一个与 outer 相同的函数,以便更容易解释和可靠的值 CLOSE - 请参阅我的更新跨度>
  • 这太棒了,谢谢!但我坚持之前的建议,因为计算时间大幅增加!
【解决方案2】:

使用@Allan Cameron 提供的df 的方法将使用fuzzyjoin。首先,您将确定彼此靠近的位置。然后,您将从数据框中删除它们。我提供的示例使用 1 公里的距离。

library(dplyr)
library(fuzzyjoin)

df <- data.frame(latitude  = runif(1000, 51, 54),
             longitude = runif(1000, 8, 13))


close <- df %>% fuzzyjoin::geo_left_join(df, max_dist = 1, unit = "km") %>% 
  filter((longitude.x == longitude.y & latitude.x == latitude.y) == FALSE) %>% 
  rename(longitude = longitude.x, latitude = latitude.x) %>% 
  select(longitude, latitude)


df %>% 
  anti_join(close)

【讨论】:

  • 谢谢罗伯特,但即使我以你的例子为例,我仍然会收到此错误:Fehler in UseMethod("tbl_vars") : nicht anwendbare Methode für 'tbl_vars' auf Objekt der Klasse "function"安格温德特。
  • 奇怪。这在我的机器上很好。这一定是您的软件包安装问题或某些奇怪的系统特定问题
  • 也许其他一些包重载了一些方法?
  • 尝试来自fuzzyjoin 本身rdocumentation.org/packages/tigris/versions/0.9.4/topics/… 的示例。我最初的示例使用 :: 显式提供了命名空间,所以我确定它是如何重载的
  • 谢谢罗伯特,我会检查一下。到目前为止,我将使用 Allan 提供的解决方案。 Henrik 建议的 R 中的邻近空间过滤我尝试了函数细化。遗憾的是,它效率不高,计算时间很长,也没有产生好的结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-16
  • 1970-01-01
  • 1970-01-01
  • 2012-03-29
  • 2013-06-12
相关资源
最近更新 更多