微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

R data.table 中具有阈值窗口的累积和

如何解决R data.table 中具有阈值窗口的累积和

我想计算数据集中 n 行的滚动总和,其中窗口大小“n”取决于总和本身。例如,我想在滚动时间总和超过 5 分钟时滑动窗口。基本上,我想计算这个人在过去 5 分钟内走过的距离,但时间步长不是等距的。为了清楚起见,这里有一个虚拟的 data.table(最后两列是必需的):

我正在 R 中寻找 data.table 解决方

输入数据表:

ID 距离 时间
1 2 2
1 4 1
1 2 1
1 2 2
1 3 3
1 6 3
1 1 1

期望的输出

ID 距离 时间 5.min.rolling.distance 5.min.rolling.time
1 2 2 不适用 不适用
1 4 1 不适用 不适用
1 2 1 不适用 不适用
1 2 2 10 6
1 3 3 5 5
1 6 3 9 6
1 1 1 10 7

解决方法

这是一个适用于 double 时间单位的解决方案,以及适用于 integer 时间单位的更简单的解决方案。我在 10,000 条记录上测试了 double 解决方案,并在我 2015 年的笔记本电脑上立即执行。我无法保证 40 GB 数据的性能。

如果您想概括此代码,我会查看 RcppRoll package 并学习如何在 R 中实现 C++ 代码。

具有 double 个时间单位的解决方案

我把它分解成两个问题。首先,通过回顾直到我们到达至少 5 分钟(或用完数据)来计算窗口大小。其次,取从当前观察到回溯单元的距离和时间之和。

R 中的错​​误循环代码通常会尝试“增长”向量,预先分配向量长度然后更改其中的元素可以极大地提高效率。

input <- data.frame(
  dist = c(2,4,2,3,6,1),time = c(2,1,1)
)

var_window_cumsum <- function(input,MIN_TIME) {
  
  if(is.null(input$time) | is.null(input$dist)) {
    stop("input must have variables time and dist that record the row's duration and distance traveled.")
  }
  
  n <- nrow(input)
  
  # First,figure out how far we need to look back to,this vector will store
  # the position of the first record that gets our target record up to 5 min or
  # more. If we cant look back to 5 min,we leave it as NA.
  time_indx = rep(NA_integer_,length = n) # always preallocate your vector!
  for(time in (1:n)) {
    prior = time # start at self in case observation is already >= MIN_TIME
    while(sum(input$time[time:prior]) < MIN_TIME & prior > 1) {
      prior = prior - 1
    }
    
    # if we cant look back to our minimum time,leave the indx as NA
    if (sum(input$time[time:prior]) >= MIN_TIME) {
      time_indx[time] = prior 
    }
  }
  
  # Now that we know how far to look back,its easy to find out the total distance
  # and total time.
  dist5 =  rep(NA_integer_,n)
  time5 =  rep(NA_integer_,n)
  for (i in 1:n) {
    dist5[i] <- ifelse(!is.na(time_indx[i]),sum(input$dist[i:time_indx[i]]),NA)
    time5[i] <- ifelse(!is.na(time_indx[i]),sum(input$time[i:time_indx[i]]),NA)
  }
  
  cbind(input,window_dist = dist5,window_time = time5,window_start = time_indx)
}

# output looks good 
# Warning: example data does not include exhaustive cases 
# I have not setup thorough testing
var_window_cumsum(input,5)
# Test on a larger dataset,10k records
set.seed(1234)
n <- 10000
med_input <- data.frame(
  dist = sample(1:5,n,replace = TRUE),time = sample(1:60,replace = TRUE) / 10
)

# you should inspect this to make sure there are no errors
med_output <- var_window_cumsum(med_input,5)

具有 integer 个时间单位的解决方案

如果您的时间单位是整数并且您的数据不是太大,则它可能适用于 complete 您的数据集。这是一个小技巧,但在这里我创建了一个从开始时间到最大时间的连续 timeid 变量,并为每个整数时间单位创建一行。从那里很容易计算最后五个时间单位的滚动累积总和。最后,我们删除了我们添加的所有假行(您要确保这样做,因为它们将具有无效的累积总和数据。另外,重要的是要注意我使用 roll_sumr 而不是 {{1} }; roll_sum 在前 4 个单位的输出向量左侧包含 4 个填充 NA。

roll_sumr

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。