R语言使用一个数据框的datetime筛选另一数据框并按UserId分组汇总
解决方案
基于dplyr的实现(语法友好,适合中小数据量)
依赖dplyr 1.1.0及以上版本,使用内置非等值连接语法实现匹配,代码可读性高:
library(dplyr) # 定义取分类变量众数的函数,多个最高频时返回第一个 get_mode <- function(x) { x_clean <- na.omit(x) if (length(x_clean) == 0) return(NA_character_) freq_tab <- table(x_clean) names(freq_tab)[which.max(freq_tab)] } result <- df2 %>% # 按用户+时间区间匹配df1的对应数据 left_join(df1, join_by(UserId, DateTime_Start >= OrigTime, DateTime_Start <= LastTime)) %>% # 按df2的唯一行分组,保证最终结果行数和df2完全一致 group_by(UserId, OrigTime, LastTime, events_recount) %>% # 每组按时间升序排列,保证相邻行的时序正确性 arrange(DateTime_Start, .by_group = TRUE) %>% # 计算所需的4个指标 summarise( total_duration = sum(Duration, na.rm = TRUE), avg_duration = mean(Duration, na.rm = TRUE), most_common_genre = get_mode(Genre), genre_switch_times = sum(Genre != lag(Genre, default = first(Genre)), na.rm = TRUE), .groups = "drop" )
运行后result即为添加了4个汇总指标的最终df2,示例数据中所有Genre均为Sport,因此genre_switch_times列全为0,符合预期。
基于data.table的实现(效率更高,适合大数据量)
如果数据量达十万行以上,推荐使用data.table方案,运算效率提升明显:
library(data.table) setDT(df1) setDT(df2) # 非等值连接+分组汇总一步完成 result_dt <- df1[df2, on = .(UserId, DateTime_Start >= OrigTime, DateTime_Start <= LastTime), by = .EACHI, .( total_duration = sum(Duration, na.rm = TRUE), avg_duration = mean(Duration, na.rm = TRUE), most_common_genre = get_mode(Genre), genre_switch_times = sum(Genre != shift(Genre, fill = first(Genre)), na.rm = TRUE) )][, setnames(.SD, c("DateTime_Start", "DateTime_Start.1"), c("OrigTime", "LastTime"))][]
内容的提问来源于stack exchange,提问作者metaltoaster
相关产品推荐
相关产品推荐

