满足条件时的连续小时数总和

Sum consecutive hours when condition is met

我有一个包含时间戳和数字变量的数据框,数据每小时记录一次。最终,我很想知道变量处于或低于某个值的平均小时数。例如,var1 等于或低于 4 的平均小时数是多少?数据帧中缺少时间戳,因此如果时间不连续,则需要重新计算总和。

在示例数据框中,生成了列 HoursBelow5RunningGroup 'by hand',如果我可以通过编程方式创建这些列,我可以过滤以删除 RunningGroup与大于 4 的 var1 值关联的 s,然后使用 dplyr::slice 获得每组的最大值 HoursBelow5。然后我可以找到这些值的平均值。

因此,在这种方法中,我需要创建重新启动的累积总和 HoursBelow5,它会在不满足条件 var1<5 或时间戳不是连续小时数时重新启动。然后我可以使用 ifelse 语句来创建 RunningGroup 变量。这可能吗?我可能缺乏找到程序的行话。 Cumsumlag 看起来很有希望,但我还没有构建一个执行上述操作的过程。

或者,使用时间戳可能有更聪明的方法。

编辑:结果合并了以下答案中的代码

df1 <- df %>%
  group_by(group = data.table::rleid(var1 > 4), 
           group1 = cumsum(ts - lag(ts, default = first(ts)) > 3600)) %>%
  mutate(temp = row_number() * (var1 <= 4)) %>%
  ungroup() %>%
  filter(var1 <= 4) %>% 
  select(ts, var1, temp)

df2 <- df1 %>% mutate(temp2 = ifelse(temp==1, 1, 0), 
                      newgroup = cumsum(temp2))

df3 <- df2 %>% group_by(newgroup) %>% slice(which.max(temp))
mean(df3$temp)

# example dataframe with desired output columns to then get actual output
df <- structure(list(ts = structure(c(-2208967200, -2208963600, -2208960000, 
-2208956400, -2208952800, -2208949200, -2208945600, -2208942000, 
-2208938400, -2208934800, -2208931200, -2208927600, -2208924000, 
-2208913200, -2208909600, -2208906000, -2208902400, -2208898800, 
-2208895200, -2208891600, -2208888000, -2208884400, -2208880800, 
-2208877200, -2208852000, -2208848400, -2208844800, -2208841200, 
-2208837600, -2208834000, -2208830400, -2208826800, -2208823200, 
-2208819600, -2208816000, -2208812400, -2208808800, -2208805200, 
-2208801600), class = c("POSIXct", "POSIXt"), tzone = ""), var1 = c(1L, 
3L, 4L, 5L, 4L, 3L, 5L, 6L, 7L, 8L, 3L, 2L, 2L, 2L, 3L, 3L, 2L, 
2L, 1L, 1L, 1L, 1L, 4L, 4L, 3L, 9L, 3L, 3L, 3L, 2L, 2L, 3L, 4L, 
5L, 3L, 2L, 1L, 2L, 3L), HoursBelow5 = c(1L, 2L, 3L, 0L, 1L, 
2L, 0L, 0L, 0L, 0L, 1L, 2L, 3L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 
9L, 10L, 11L, 1L, 0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 0L, 1L, 2L, 
3L, 4L, 5L), RunningGroup = c(1L, 1L, 1L, 2L, 3L, 3L, 4L, 5L, 
6L, 7L, 8L, 8L, 8L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 
10L, 11L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 13L, 14L, 14L, 14L, 
14L, 14L), NotContinuous = c("", "", "", "", "", "", "", "", 
"", "", "", "", "", "NC", "", "", "", "", "", "", "", "", "", 
"", "NC", "", "", "", "", "", "", "", "", "", "", "", "", "", 
"")), row.names = c(NA, -39L), class = "data.frame")

使用 dplyrdata.table::rleid 的一种方法可能是

library(dplyr)

df %>%
   group_by(group = data.table::rleid(var1 > 4), 
            group1 = cumsum(ts - lag(ts, default = first(ts)) > 3600)) %>%
   mutate(temp = row_number() * (var1 <= 4)) %>%
   ungroup() %>%
   select(ts, var1, HoursBelow5, temp)

#   ts                   var1 HoursBelow5  temp
#   <dttm>              <int>       <int> <int>
# 1 1900-01-01 12:46:46     1           1     1
# 2 1900-01-01 13:46:46     3           2     2
# 3 1900-01-01 14:46:46     4           3     3
# 4 1900-01-01 15:46:46     5           0     0
# 5 1900-01-01 16:46:46     4           1     1
# 6 1900-01-01 17:46:46     3           2     2
# 7 1900-01-01 18:46:46     5           0     0
# 8 1900-01-01 19:46:46     6           0     0
# 9 1900-01-01 20:46:46     7           0     0
#10 1900-01-01 21:46:46     8           0     0
# … with 29 more rows

temp 列是以编程方式生成的列,HoursBelow5 保留原样用于比较目的。如果您还需要 RunningGroup,则可以同时使用 groupgroup1