我有一系列关于POSIXlt格式的GPS位置。我想要分组并保留仅花费超过5分钟(300秒)appart的位置。
我使用子集(diff())在两个连续位置之间的时间间隔(以秒为单位)。我面临的问题是我的前三个位置每个都是5分钟,所以R不会返回任何一个(同样的事情在我的数据框架中进一步发生)
我想得到的是位置#1和#3(10分钟的appart)。 我希望并放弃#2,因为距离#1只有5分钟,然后检查下一个位置是否距离我保留的最后一个位置是5分钟。
我该怎么办?
谢谢, 本
答案 0 :(得分:2)
一种可能的方法是diff
,删除与之前观察结果太接近的任何内容,并重复直到您不删除任何内容。然而,对于具有密集间隔观测值的大型数据集而言,这可能是非常低效的。
在一次通过中执行此操作的方法是循环观察,在跳过与最后保留的观察结果太接近的观察时累积时间差异:
# Use for loop to determine which to keep
pick.obs <- function(diffs, limit) {
keep <- c(T, rep(F, length(diffs)))
acc <- 0
for (i in seq_along(diffs)) {
acc <- acc + diffs[i]
if (acc > limit) {
keep[i+1] <- T
acc <- 0
}
}
return(keep)
}
# Observations at time 0, 300, 500, 700, 1700; limit 600 seconds
obs.times <- c(0, 300, 500, 700, 1700)
pick.obs(diff(obs.times), 600)
[1] TRUE FALSE FALSE TRUE TRUE
这种方法的一个问题是,与向量化运算符相比,R中的for
循环较慢。我们可以通过使用Rcpp
包在C ++中实现for for循环(仅进行小的语法更改)来重新获得此速度:
library(Rcpp)
pick.obs2 <- cppFunction(
"LogicalVector pickObs(NumericVector diffs, const double limit) {
int n = diffs.size();
LogicalVector keep(n + 1, false);
keep[0] = true;
double acc = 0;
for (int i=0; i < n; ++i) {
acc += diffs[i];
if (acc > limit) {
keep[i+1] = true;
acc = 0;
}
}
return keep;
}")
我们可以使用microbenchmark
将纯R版本的性能与Rcpp版本进行比较:
# Reproducible example of time differences (10000 observations)
set.seed(144)
diffs <- runif(10000, 0, 20)
all.equal(pick.obs(diffs, 300), pick.obs2(diffs, 300))
# [1] TRUE
# Benchmark
library(microbenchmark)
microbenchmark(pick.obs(diffs, 300), pick.obs2(diffs, 300))
# Unit: microseconds
# expr min lq mean median uq max neval
# pick.obs(diffs, 300) 4494.029 4947.9140 6058.83941 5128.2535 6154.653 38302.461 100
# pick.obs2(diffs, 300) 19.877 21.2015 32.02145 30.8515 34.654 178.031 100
Rcpp
版本在长度10000的向量上快约200倍。此加速是否重要完全取决于问题的大小(例如,您可能不介意等待5毫秒的长度向量10,000)。