我正在模拟研究中使用 GPS 数据,这意味着我所有的小效率低下都会再次困扰我。
更大的问题之一是停止检测算法的实现。第一步是生成候选停靠点,我在其中识别时间和空间上接近的坐标。
这是一些玩具数据:
library(data.table)
gcdist <- function(lat1, lon1, lat2, lon2){
sqrt((12430*abs(lat1 - lat2)/180)^2 +
((24901*abs(lon1 - lon2)/360) * cos((lat1+lat2)/2))^2)
}
time <- rev(Sys.time() - seq(60, 30*60, 60))
lat <- cumsum(c(55, rnorm(29, 0, sd = .003)))
lon <- cumsum(c(5.2, rnorm(29, 0, sd = .003)))
id <- 1:30
dt <-data.table(id, time, time_dup = time, lon, lat)
dt[, time_window := time + 60*3]
setkey(dt, time, time_window)
我目前正在做的事情使用 data.table 中的 foverlap。数据表友好的解决方案是必须的,因为整个数据集接近 8GB。
这不够高效,无法在适当的时间线上运行我的模拟研究,而且也不是很精确。因为我只在三分钟的窗口内查看然后停止,所以我必须找到处理组合它们的方法。
# Current setup
setkey(dt, time, time_window)
temp <- foverlaps(dt, dt, by.y = c("time", "time_window"), by.x = c("time", "time_dup"), type = "within")
temp[, dist := gcdist(lat, lon, i.lat, i.lon)]
temp[dist < .5, within_stop := TRUE]
temp[, candidate_stop := all(dist < .5), id]
setkey(temp, id)
setkey(dt, id)
dt[temp, candidate_stop := i.candidate_stop]
setkey(temp, i.id)
dt[temp, within_stop := i.within_stop]
这更接近我应该做的事情,但对于 8GB 的数据来说太麻烦了。
current_stop <- dt[1, ]
for (i in seq_len(nrow(dt))) {
dist <- gcdist(current_stop[, lat], current_stop[, lon],
dt[i, lat], dt[i, lon])
if(abs(dist) > .5) current_stop <- dt[i]
dt[i:nrow(dt), stop_id := current_stop[, id]]
}
我有预感 data.table 的滚动连接或 frollapply 对我有用。我不断地阅读这些页面并尝试示例,但我无法完全使其发挥作用。我认为我应该能够滚动应用距离窗口函数,直到距离大于某个截止值,然后重新启动,但如果我能弄清楚如何做到这一点,这会打败我。
最佳答案
我相信这应该会有所帮助,尽管您的 within_stop
变量可能存在一些问题。
dt[dt,
on = .(time >= time, time_dup <= time_window),
c("within_stop", "candidate_stop") := {
within_stop = gcdist(lat, lon, i.lat, i.lon) < 0.5
.(within_stop = first(within_stop), ## I am least sure about this.
candidate_stop = all(within_stop))
},
by = .EACHI]
dt
在我的机器上,该数据集的速度大约是该数据集的两倍。我提到 within_stop
因为它可能在每个加入组内有所不同。也就是说,有时它都是真的,而有时它可能是混合的。如果存在多个匹配项,我无法确定 dt[dt, :=]
默认值是什么,尽管我认为它可能是第一个
。
为了稍微快一点,您可能可以使用 rcpp 编译的代码您可以在其中通过短路实现 gcdist() ,以便它仅返回 bool 值。这样,您就不必分配距离向量和 bool 向量是否在您的容差范围内。这似乎有效,尽管对于我当前的数据集来说,性能提升很小。
bool gcdist_short_circuit(NumericVector lat, NumericVector lon,double i_lat, double i_lon) {
bool out = TRUE;
for (int i = 0; i < lat.size(); i++) {
if (sqrt(pow(12430*abs(lat[i] - i_lat)/180, 2) + pow((24901*abs(lon[i] - i_lon)/360) * cos((lat[i]+i_lat)/2),2)) >= 0.5) {
out = FALSE;
break;
}
}
return(out);
}
关于r - 如何使用 data.table 有效地聚合时间和距离窗口?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65031351/