【问题标题】:Subsetting rows in R based on time intervals根据时间间隔对 R 中的行进行子集化
【发布时间】:2015-04-13 13:07:11
【问题描述】:

我有一系列关于 POSIXlt 格式的 GPS 位置。我想子集并仅保留花费超过 5 分钟(300 秒)的位置。

我使用子集(diff())在两个连续位置之间的时间间隔(以秒为单位)。我面临的问题是我的前三个位置每个间隔 5 分钟,所以 R 不会返回任何一个(沿着我的数据框进一步发生同样的事情)

我想要的是#1 和#3 的位置(相隔 10 分钟)。 我想要删除 #2,因为它距离 #1 5 分钟,然后检查下一个位置是否距离我保留的最后一个位置 > 5 分钟。

我应该如何进行?

谢谢, 本

【问题讨论】:

  • 你能包含一个使用dput()的示例数据集吗?

标签: r time subset intervals


【解决方案1】:

一种可能的方法是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 的向量) .

【讨论】:

  • 我在这里有几乎相同的问题:[link]stackoverflow.com/questions/38504957/…。您能否提供更多代码来应用您提供的第二种解决方案(更快的...)
  • “diffs”的长度比pick.obs2的结果小1。这是为什么呢?
  • @Nova 抱歉,我不确定我是否遵循了这个问题。你说的是哪段代码?
  • 在你的例子中,如果你运行diffs &lt;- runif(100, 0, 20)然后运行keep &lt;- pick.obs2(diffs, 300)diffs的长度与keep不同。如果你想使用keepdiff中删除obs,长度不相等。
  • @Nova 明白了。 pick.obs2 将原始列表中连续元素之间的差异作为参数。因此,如果 diffs 的长度为 100,那么它一定来自某个长度为 101 的原始列表。因此,如果您有一个像 obs.times &lt;- c(0, 300, 500, 700, 1700) 这样的原始向量,那么您可以确定是否将每个向量保留为 pick.obs2(diff(obs.times), 300)
猜你喜欢
  • 2021-12-03
  • 2019-03-19
  • 2013-10-25
  • 1970-01-01
  • 2017-11-24
  • 2019-01-30
  • 2012-07-07
  • 2012-01-23
  • 1970-01-01
相关资源
最近更新 更多