一种可能的方法是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 循环(只做小的语法更改)来重新获得这个速度:
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 的向量) .