R - 根据位置将纬度/经度点的巨大数据帧分组

标签 r optimization

我是 R 的新手,但我听说使用 for 确实是个坏主意。循环。我有使用它们的工作代码,但我想改进它,因为大数据非常慢。我已经有了一些如何改进算法的想法,但我不知道如何将其矢量化,或者在没有 for 的情况下进行。循环。

我只是将 lat/lng 点分组为一个以半径为参数的圆圈。

该函数的示例输出(仅填充 circle_id 列中的值),半径设置为 100 米:

[1] "Locations: "
   latitude  longitude sensor_time sensor_time2         circle_id
   48.15144  17.07569  1447149703  2015-11-10 11:01:43         1
   48.15404  17.07452  1447149743  2015-11-10 11:02:23         2
   48.15277  17.07514  1447149762  2015-11-10 11:02:42         3
   48.15208  17.07538  1447149771  2015-11-10 11:02:51         1
   48.15461  17.07560  1447149773  2015-11-10 11:02:53         4
   48.15139  17.07562  1447149811  2015-11-10 11:03:31         1
   48.15446  17.07517  1447149866  2015-11-10 11:04:26         2
   48.15266  17.07330  1447149993  2015-11-10 11:06:33         5

所以我有 2 个 for 循环,loop1 遍历每一行,loop2 遍历每个以前的 circle_id,并检查 loop1 的当前位置是否在 loop2 的现有圆的半径内。每个 circle_id 的中心是在所有先前的半径之外找到的第一个位置。

这是代码:
init_circles = function(datfr, radius) {
  cnt = 1
  datfr$circle_id[1] = 1
  longitude = datfr$longitude[1]
  latitude = datfr$latitude[1]
  circle_id = datfr$circle_id[1]
  datfr2 <- data.frame(longitude, latitude, circle_id)

  for (i in 2:NROW(datfr)) {
      for (j in 1:NROW(datfr2)) {
        tmp = distHaversine(c(datfr$longitude[i],datfr$latitude[i]) ,c(datfr2$longitude[j],datfr2$latitude[j]))
        if (tmp < radius){
          datfr$circle_id[i] = datfr2$circle_id[j]
          break
        }
      }
      if (datfr$circle_id[i]<1){
        cnt = cnt +1
        datfr$circle_id[i] = cnt
        datfr2[nrow(datfr2)+1,] = c(datfr$longitude[i],datfr$latitude[i],datfr$circle_id[i])
      }
  }
  return(datfr)
}

数据中心 是没有设置 circle_id 的输入数据帧, datfr2 是一个包含现有圆圈的临时数据框。

编辑:这是一个视觉输出:
enter image description here

您可以看到这些圆圈的用途,上面的红色圆圈还有 21 个其他位置适合其半径(21 + 1 原始 = 22)

非常感谢你的帮助,
阿莱娜

最佳答案

我假设我们有一个数据框 circles每个圆的中心和半径,并且您问题中发布的示例数据位于名为 dat 的数据框中.下面的代码将距离的计算向量化并使用 lapply计算每个点到每个圆中心的距离,并确定每个点是否在该圆的半径内。

library(geosphere)

# We'll check the distance of each data point from the center of each 
#  of these circles
circles = data.frame(ID=1:2, lon=c(17.074, 17.076), lat=c(48.1513, 48.15142), 
                     radius=c(180,190))

datNew = lapply(1:nrow(circles), function(i) {

  df = dat

  df$dist = distHaversine(df[,c("longitude", "latitude")], 
                          circles[rep(i,nrow(df)), c('lon','lat')])

  df$in_circle = ifelse(df$dist <= circles[i, "radius"], "Yes", "No")

  df$circle_id = circles[i, "ID"]

  df

})

datNew = do.call(rbind, datNew)

datNew

   latitude longitude sensor_time sensor_time2    time3      dist in_circle circle_id
1  48.15144  17.07569  1447149703   2015-11-10 11:01:43 126.47756       Yes         1
2  48.15404  17.07452  1447149743   2015-11-10 11:02:23 307.45048        No         1
3  48.15277  17.07514  1447149762   2015-11-10 11:02:42 184.24465        No         1
4  48.15208  17.07538  1447149771   2015-11-10 11:02:51 134.32601       Yes         1
5  48.15461  17.07560  1447149773   2015-11-10 11:02:53 387.15358        No         1
6  48.15139  17.07562  1447149811   2015-11-10 11:03:31 120.73138       Yes         1
7  48.15446  17.07517  1447149866   2015-11-10 11:04:26 362.34236        No         1
8  48.15266  17.07330  1447149993   2015-11-10 11:06:33 160.07179       Yes         1
9  48.15144  17.07569  1447149703   2015-11-10 11:01:43  23.13059       Yes         2
10 48.15404  17.07452  1447149743   2015-11-10 11:02:23 311.68096        No         2
11 48.15277  17.07514  1447149762   2015-11-10 11:02:42 163.29068       Yes         2
12 48.15208  17.07538  1447149771   2015-11-10 11:02:51  86.70762       Yes         2
13 48.15461  17.07560  1447149773   2015-11-10 11:02:53 356.34955        No         2
14 48.15139  17.07562  1447149811   2015-11-10 11:03:31  28.41890       Yes         2
15 48.15446  17.07517  1447149866   2015-11-10 11:04:26 343.97933        No         2
16 48.15266  17.07330  1447149993   2015-11-10 11:06:33 243.44024        No         2


所以我们现在有一个数据框告诉我们每个点是否在给定的圆内。数据框是长格式的,意思是有n原始数据框中每个点的行 dat ,其中 ncircles 中的行数数据框。从这里,您可以进行进一步处理,例如只为多个圆圈中的每个点保留一行,等等。

这是一个例子。我们将返回一个数据框,列出一个点在哪个圆圈内,如果该点不在任何圆圈内,则返回“无”:
library(dplyr)

datNew %>%
  group_by(latitude, longitude) %>% 
  summarise(in_which_circles = if(any(in_circle=="Yes")) paste(circle_id[in_circle=="Yes"], collapse=",") else "None")

  latitude longitude in_which_circles
     <dbl>     <dbl>            <chr>
1 48.15139  17.07562              1,2
2 48.15144  17.07569              1,2
3 48.15208  17.07538              1,2
4 48.15266  17.07330                1
5 48.15277  17.07514                2
6 48.15404  17.07452             None
7 48.15446  17.07517             None
8 48.15461  17.07560             None

关于R - 根据位置将纬度/经度点的巨大数据帧分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40897882/

相关文章:

r - 表格的data.table 与表格的data.frame 有很大不同

r - 将 RStudio Default R Notebook 更改为空白

r - R 中的更高级别函数 - 是否有官方的 compose 运算符或 curry 函数?

oracle - 如何选择和优化oracle索引?

c++ - 为什么我会看到这些函数之间存在如此巨大的性能差异?

excel - 优化 VBA 脚本以组合和整合

R:处理光栅包中的 sf 对象

r - 向密度图添加百分位线

c++ - 加速 CPLEX C++ 代码

scala - Scala 编译器会提升正则表达式吗