如何计算拆分为数据帧不同行的事件的持续时间

How can I compute the duration of events splited in different rows of a dataframe

我正在处理一个处理过 gps 位置的数据框。我有三个变量:id,它对应于每个人的标识符,TimeStamp,它表示 gps 信号的时刻,perimeter 表示信号是否发生在给定的范围内周长。我想创建一个 table,其中以正确的出现顺序在给定周界内或之外花费的时间。

这是一个可重现的例子:

df <- data.frame(id=rep(1, 10),
                 TimeStamp=seq(as.POSIXct("2020-01-01 12:00:00"), 
                               as.POSIXct("2020-01-01 16:30:00"), 
                               length.out = 10),
                 perimeter=c(NA, NA, NA, "p1", "p1", "p1", NA, NA, "p2", "p2"))

我想要的输出是这样的:

id perimeter time
1  NA        1.5
1  "p1"      1.5
1  NA        1
1  "p2"      1

我已经找到了使用 rle() 函数的解决方案:

df[is.na(df$perimeter),]$perimeter <- "OUT"

data.frame(perimeter=rle(df$perimeter)$value,
           time=(rle(df$perimeter)$length*30)/60)

但是,它会根据向量中重复序列的长度来估计时间,并且由于我有缺失值,所以从最后一个重复项中减去第一个重复项的时间戳会更准确。

这是一个data.table解决方案:

library(data.table)
setDT(df)
df[, nextTimeStamp := shift(TimeStamp, -1L), by = id]
df[, .( unclass(nextTimeStamp[.N] - TimeStamp[1L]) / 60^2), by = .(id, rleid(perimeter))]

#    id rleid  V1
# 1:  1     1 1.5
# 2:  1     2 1.5
# 3:  1     3 1.0
# 4:  1     4  NA

dplyr 解决方案:

df %>% 
  mutate(perimeter = forcats::fct_explicit_na(df$perimeter),
         visit = cumsum(perimeter != lag(perimeter) | is.na(lag(perimeter)))) %>% 
  group_by(id, visit, perimeter) %>% 
  summarise(time = difftime(max(TimeStamp) + 1800, min(TimeStamp), unit = "hour")) %>%
  ungroup() %>% select(-visit)

#> # A tibble: 4 x 3
#>      id perimeter time     
#>   <dbl> <fct>     <drtn>   
#> 1     1 (Missing) 1.5 hours
#> 2     1 p1        1.5 hours
#> 3     1 (Missing) 1.0 hours
#> 4     1 p2        1.0 hours