You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 23:45:03