如何按小时统计事件发生次数(含无事件小时的0值)
解决方案
我们可以通过生成完整的小时时间序列、计算小时级有效观测时长、关联取食次数统计结果这三步实现需求,全程基于tidyverse工具链完成。
1. 准备示例数据
先构造一份符合你描述的观测数据,方便后续演示:
library(tidyverse) library(lubridate) # 示例观测数据:包含观测起止时间、取食时间、性别 obs_data <- tibble( obs_id = c(1, 1, 1, 2, 2), obs_start = ymd_hms(c("2024-05-20 09:30:00", "2024-05-20 09:30:00", "2024-05-20 09:30:00", "2024-05-20 14:15:00", "2024-05-20 14:15:00")), obs_end = ymd_hms(c("2024-05-20 16:45:00", "2024-05-20 16:45:00", "2024-05-20 16:45:00", "2024-05-20 17:20:00", "2024-05-20 17:20:00")), feeding_time = ymd_hms(c("2024-05-20 10:12:00", "2024-05-20 12:45:00", "2024-05-20 16:05:00", "2024-05-20 14:30:00", "2024-05-20 16:50:00")), sex = c("male", "female", "male", "female", "male") )
2. 生成完整的小时时间序列
先确定观测覆盖的所有小时区间,生成从最早观测开始时间的整点到最晚观测结束时间的整点的完整序列,确保无取食的小时也被纳入:
# 获取观测时间范围的首尾整点 time_range <- range(floor_date(c(obs_data$obs_start, obs_data$obs_end), unit = "hour")) # 生成所有覆盖的小时 full_hours <- tibble(hour_start = seq(time_range[1], time_range[2], by = "hour")) %>% mutate(hour_end = hour_start + hours(1))
3. 计算每个小时的有效观测时长
有效观测时长是该小时的时间区间与所有观测时间段的交集总时长,用时间区间工具计算:
# 先把观测数据转换为区间格式 obs_intervals <- obs_data %>% distinct(obs_id, obs_start, obs_end) %>% mutate(obs_interval = interval(obs_start, obs_end)) # 计算每个小时与所有观测区间的交集总时长(单位:分钟) hourly_duration <- full_hours %>% rowwise() %>% mutate( hour_interval = interval(hour_start, hour_end), effective_duration = sum( as.duration(intersect(hour_interval, obs_intervals$obs_interval)) / dminutes(1), na.rm = TRUE ) ) %>% ungroup() %>% select(hour_start, effective_duration)
4. 统计每个小时的取食次数
先按小时分组统计取食次数,再和完整小时序列左连接,缺失的次数填充为0:
# 统计有取食记录的小时的次数 feeding_counts <- obs_data %>% mutate(hour_start = floor_date(feeding_time, unit = "hour")) %>% count(hour_start, name = "feeding_count") # 关联完整小时序列,填充无取食小时的次数为0 final_result <- hourly_duration %>% left_join(feeding_counts, by = "hour_start") %>% mutate(feeding_count = replace_na(feeding_count, 0)) %>% # 可选:格式化小时显示 mutate(hour_label = format(hour_start, "%Y-%m-%d %H:00")) %>% select(hour_label, effective_duration, feeding_count)
最终结果示例
运行代码后,final_result会输出包含所有小时的统计结果:
# A tibble: 9 × 3 hour_label effective_duration feeding_count <chr> <dbl> <dbl> 1 2024-05-20 09:00 30 0 2 2024-05-20 10:00 60 1 3 2024-05-20 11:00 60 0 4 2024-05-20 12:00 60 1 5 2024-05-20 13:00 60 0 6 2024-05-20 14:00 45 1 7 2024-05-20 15:00 60 0 8 2024-05-20 16:00 60 2 9 2024-05-20 17:00 20 0
关键思路说明
- 用
floor_date和seq生成完整小时序列,避免遗漏无取食的小时; - 通过时间区间的交集计算有效观测时长,准确反映每个小时内实际观测的时间;
- 左连接取食次数统计结果,用
replace_na填充0,满足显示所有小时的需求。
内容的提问来源于stack exchange,提问作者Tim
相关产品推荐
相关产品推荐

