R语言:如何按对应日期对循环聚合小时级数据集?
问题描述
我有一份全年小时级数据集(共37个变量、8760行),已经用独立R脚本run_seq.R实现了单个日期范围的小时数据聚合,代码如下:
Date_From <- '2022-04-01' Date_To <- '2022-04-02' DF_hour <- (DfDHW %>% filter(as.Date(Hour) >= as.Date(Date_From) & as.Date(Hour) <= as.Date(Date_To))) dummy <- as.numeric(DF_hour$Var*0+1) dfdate <- aggregate(.~dummy, DFhour, sum)
这段代码可以正常运行,但我需要循环处理多组连续日期对。已经生成了日期起始序列dates_from、结束序列dates_to及序列号seq_num并组合成数据框:
dates_from <- seq(as.Date("2022-04-01"), as.Date("2022-04-10"), by=1) dates_to <- seq(as.Date("2022-04-02"), as.Date("2022-04-11"), by=1) seq_num <- as.numeric(format(dates_from, format = "%d")) df <- cbind.data.frame(dates_from, dates_to, seq_num)
但当前的for循环会聚合所有10天的数据,无法匹配对应序列号的日期对(比如第1次循环用seq_num=1对应的日期对,第2次用seq_num=2对应的日期对)。请问怎么实现这个需求?有没有更优雅的实现方式?
数据集DfDHW的结构示例:
| Hour | Var1 | Var2 |
|---|---|---|
| 2022-01-01 01:00:00 | 1.480 | 1.480 |
| 2022-01-01 02:00:00 | 0.957 | 0.957 |
dput(head(DfDHW))输出:
structure(list(Hour = structure(c(1640995200, 1640998800, 1641002400, 1641006000, 1641009600, 1641013200), class = c("POSIXct", "POSIXt" ), tzone = "Europe/Stockholm"), Var1 = c(1.48022736417965, 0.957129616195086, 0.67616277119973, 0.516807667014335, 0.500124643187317, 0.596748739907164), Var2 = c(1.48022736417965, 0.957129616195086, 0.67616277119973, 0.516807667014335, 0.500124643187317, 0.596748739907164 ), Var3 = c(1.48022736417965, 0.957129616195086, ...
解决方案
方法1:修正for循环逻辑
你的问题核心是循环时没有正确提取每组对应的日期范围,直接遍历df的每一行即可解决:
# 初始化空列表存储结果 result_list <- list() for (i in 1:nrow(df)) { # 取出当前行的日期对和序列号 current_from <- df$dates_from[i] current_to <- df$dates_to[i] current_seq <- df$seq_num[i] # 过滤目标日期范围的数据 DF_hour <- DfDHW %>% filter(as.Date(Hour) >= current_from & as.Date(Hour) <= current_to) # 聚合数据(注意修正原代码的笔误:DFhour → DF_hour) dummy <- as.numeric(DF_hour$Var1 * 0 + 1) # 替换成你实际要用来生成dummy的变量 dfdate <- aggregate(. ~ dummy, DF_hour, sum) # 添加上序列号,方便后续识别分组 dfdate$seq_num <- current_seq # 将结果存入列表 result_list[[i]] <- dfdate } # 合并所有结果为单个数据框 final_result <- do.call(rbind, result_list)
方法2:更优雅的函数式编程(dplyr + purrr)
用purrr的pmap可以直接对df的每一行应用聚合逻辑,代码更简洁,无需手动管理循环索引:
library(dplyr) library(purrr) # 定义日期范围聚合函数 aggregate_date_range <- function(from_date, to_date, seq_num) { DfDHW %>% filter(as.Date(Hour) >= from_date & as.Date(Hour) <= to_date) %>% mutate(dummy = 1) %>% # 直接生成dummy列,比Var*0+1更直观 group_by(dummy) %>% summarise(across(everything(), sum, .names = "sum_{.col}"), .groups = "drop") %>% mutate(seq_num = seq_num) %>% select(-dummy) # 移除无用的dummy列 } # 应用函数并直接合并结果 final_result <- df %>% pmap_dfr(aggregate_date_range)
方法3:data.table高效处理(适合大数据场景)
如果数据集规模较大,data.table的处理速度会显著快于常规方法:
library(data.table) # 转换为data.table格式 setDT(DfDHW) # 定义聚合函数 aggregate_dt <- function(from_date, to_date, seq_num) { DfDHW[as.Date(Hour) >= from_date & as.Date(Hour) <= to_date, lapply(.SD, sum), .SDcols = patterns("Var")][, seq_num := seq_num] } # 应用函数并合并结果 final_result <- rbindlist(Map(aggregate_dt, df$dates_from, df$dates_to, df$seq_num))
关键注意点
- 原代码中的
DFhour是拼写错误,需修正为DF_hour - 生成
dummy列时,直接用mutate(dummy = 1)比Var*0+1更直观高效 - 若要聚合所有数值变量,用
across(everything(), sum)(dplyr)或lapply(.SD, sum)(data.table)无需逐个指定变量
内容的提问来源于stack exchange,提问作者SPet
相关产品推荐
相关产品推荐

