如何为BranchId、Hour、weekdays各参数组合生成未来时间戳?
问题描述
我需要为数据集中每个(BranchId, Hour, weekdays)参数组合生成未来时间戳,原始数据如下:
BranchId Hour weekdays ActivityDate Total 1 11 3 2018-02-06T00:00:00 18 1 11 3 2018-02-13T00:00:00 23 1 12 3 2018-02-06T00:00:00 15 1 12 3 2018-02-13T00:00:00 13 1 13 3 2018-02-06T00:00:00 24 1 13 3 2018-02-13T00:00:00 22
目前我只能为单个组合生成正确的未来时间戳,结果如下:
BranchId Hour weekdays ActivityDate Total 1 11 3 2018-02-06T00:00:00Z 18 1 11 3 2018-02-13T00:00:00Z 23 1 11 3 2018-02-20T00:00:00Z NA 1 11 3 2018-02-27T00:00:00Z NA 1 11 3 2018-03-06T00:00:00Z NA 1 11 3 2018-03-13T00:00:00Z NA
使用的代码如下:
min.date <- min(data$ActivityDate) max.date <- max(data$ActivityDate) unique.time <- seq(from = min.date, to = max.date, by = "week") forecast.time <- seq(from = max.date, by = observation.freq, length.out = 4 + 1)[-1] all.time <- c(unique.time, forecast.time) all.time <- data.frame(BranchId = data$BranchId[1], Hour = data$Hour[1], weekdays = data$weekdays[1],ActivityDate = all.time) # Join the combination with original data data <- join(all.time, data, by = c("BranchId","Hour", "weekdays", "ActivityDate"), type = "left")
但将该代码应用于全量数据时结果错误,无法为每个参数组合生成未来时间戳,错误结果如下:
BranchId Hour weekdays ActivityDate Total 1 11 3 2018-02-06T00:00:00Z 18 1 11 3 2018-02-13T00:00:00Z 23 1 12 3 2018-02-20T00:00:00Z NA 1 12 3 2018-02-27T00:00:00Z NA 1 13 3 2018-03-06T00:00:00Z NA 1 13 3 2018-03-13T00:00:00Z NA
请问是否需要通过多函数或循环来实现需求?
解决方案
没错,你确实需要针对每个(BranchId, Hour, weekdays)组合单独处理,而不是用整个数据集的全局日期或者只取第一行的分组值。手动写循环当然可行,但用R里的分组处理工具会更简洁高效,还能避免循环容易出错的问题。
方法1:用dplyr做分组处理(简洁易读)
先确保你安装并加载了dplyr包:
install.packages("dplyr") library(dplyr)
然后我们定义一个处理单个分组的函数,再用group_by+do把这个函数应用到每个分组上:
# 先把ActivityDate转成日期时间类型(如果还没转的话) data$ActivityDate <- as.POSIXct(data$ActivityDate) # 定义生成该分组完整时间序列的函数 generate_group_forecast <- function(group_df) { # 取当前分组的最小和最大日期 min_date <- min(group_df$ActivityDate) max_date <- max(group_df$ActivityDate) # 时间频率和你之前保持一致,这里是每周 obs_freq <- "week" # 生成已有数据的时间序列 existing_times <- seq(from = min_date, to = max_date, by = obs_freq) # 生成未来4个时间戳(和你之前的逻辑一致,length.out=4+1是为了去掉第一个重复的max_date) future_times <- seq(from = max_date, by = obs_freq, length.out = 4 + 1)[-1] # 合并已有和未来时间,构建该分组的完整时间框 all_times <- c(existing_times, future_times) full_group <- data.frame( BranchId = group_df$BranchId[1], Hour = group_df$Hour[1], weekdays = group_df$weekdays[1], ActivityDate = all_times, stringsAsFactors = FALSE ) # 和原始分组数据左连接,填充Total值,没有的就留NA left_join(full_group, group_df, by = c("BranchId", "Hour", "weekdays", "ActivityDate")) } # 对每个分组应用函数,合并结果 final_result <- data %>% group_by(BranchId, Hour, weekdays) %>% do(generate_group_forecast(.)) %>% ungroup()
方法2:用data.table处理(更高效,适合大数据集)
如果你要处理的数据集很大,data.table的速度会比dplyr快很多:
install.packages("data.table") library(data.table) # 把数据转成data.table格式 setDT(data) data$ActivityDate <- as.POSIXct(data$ActivityDate) # 分组处理每个组合 final_result <- data[, { min_date <- min(ActivityDate) max_date <- max(ActivityDate) obs_freq <- "week" existing_times <- seq(from = min_date, to = max_date, by = obs_freq) future_times <- seq(from = max_date, by = obs_freq, length.out = 4 + 1)[-1] all_times <- c(existing_times, future_times) # 构建当前分组的完整时间数据框 full_dt <- .SD[0][, ActivityDate := all_times] full_dt[, c("BranchId", "Hour", "weekdays") := .(BranchId[1], Hour[1], weekdays[1])] # 左连接原始数据 merge(full_dt, .SD, by = c("BranchId", "Hour", "weekdays", "ActivityDate"), all.x = TRUE) }, by = .(BranchId, Hour, weekdays)]
为什么之前的代码出错?
你之前的代码用了整个数据集的min.date和max.date,而且只取了data$BranchId[1]这种第一行的分组值,相当于所有组合都用了第一个分组的参数和日期范围,自然其他组合的未来时间戳就完全不对了。通过分组处理,每个(BranchId, Hour, weekdays)组合都会用自己的日期范围生成时间序列,这样就能得到正确的结果。
内容的提问来源于stack exchange,提问作者Tape
相关产品推荐
相关产品推荐

