如何在R语言中为目标DataFrame按分组及时间区间添加多独立数据框的平均温度列
如何在R中按分组计算时间区间内的平均温度并添加到DataFrame?
我有一个包含多变量的DataFrame df1,生成代码如下:
Place <- c(rep("PlaceA",14),rep("PlaceB",15)) Group_Id <- c(rep("A1",5),rep("A1",6),rep("A2",3),rep("B1",6),rep("B2",4),rep("B2",5)) Time <- as.Date(c("2018-01-15","2018-02-03","2018-02-27","2018-03-10","2018-03-18","2019-02-02","2019-03-01","2019-03-15","2019-03-28","2019-04-05","2019-04-12","2018-02-01", "2018-03-01","2018-04-07","2018-01-17","2018-01-27","2018-02-17","2018-03-03","2018-04-02","2018-04-25","2018-03-03","2018-03-18","2018-04-08","2018-04-20", "2019-01-23","2019-02-09","2019-02-27","2019-03-12","2019-03-30")) FollowUp <- c("start",paste("week",week(ymd(Time[2:5]))),"start",paste("week",week(ymd(Time[7:11]))),"start",paste("week",week(ymd(Time[13:14]))),"start",paste("week",week(ymd(Time[16:20]))),"start",paste("week",week(ymd(Time[22:24]))),"start",paste("week",week(ymd(Time[26:29])))) exprmt <- c(rep(1,5),rep(2,6),rep(3,3),rep(4,6),rep(5,4),rep(6,5)) df1 <- data.frame(Place, Group_Id, Time, exprmt, FollowUp)
df1的部分数据展示如下:
> df1 Place Group_Id Time exprmt FollowUp 1 PlaceA A1 2018-01-15 1 start 2 PlaceA A1 2018-02-03 1 week 5 3 PlaceA A1 2018-02-27 1 week 9 ...(其余数据略)
同时,每个Place对应一个独立的小时级温度记录DataFrame,示例生成代码如下:
set.seed(1032) t <- c(seq.POSIXt(from = ISOdate(2018,01,01),to = ISOdate(2018,06,01), by = "hour"),seq.POSIXt(from = ISOdate(2019,01,01),to = ISOdate(2019,06,01), by = "hour")) temp_A <- runif(length(t),min = 5, max = 25) temp_B <- runif(length(t),min = 3, max = 32) data_A <- data.frame(t,temp_A) data_B <- data.frame(t,temp_B)
data_A的头部数据展示如下:
> head(data_A) t temp_A 1 2018-01-01 12:00:00 14.24961 2 2018-01-01 13:00:00 21.64925 ...(其余数据略)
需求说明
我需要在df1中新增一列,实现以下需求:
- 按
Place、Group_Id、exprmt进行分组; - 每组的第一条记录(
FollowUp为start)对应值为NaN; - 每组后续的每条记录,计算对应
Place的温度DataFrame中,前一行Time到当前行Time之间的平均温度,并填入该列。
我尝试过的代码(未成功)
df1 <- df1 %>% group_by(Place,Group_Id,exprmt) %>% mutate( temp = case_when( FollowUp == "start" & Place == "PlaceA" ~ NA, FollowUp == FollowUp[c(2:n())] & Place == "PlaceA" ~ mean(temp_A[c(which(date(temp_A$t))==lag(Time,1):which(date(temp_A$t))==Time),2]), ) )
预期结果示例
> df1 Place Group_Id Time exprmt FollowUp expected 1 PlaceA A1 2018-01-15 1 start NaN 2 PlaceA A1 2018-02-03 1 week 5 mean temp_A between 2018-01-15 and 2018-02-03 3 PlaceA A1 2018-02-27 1 week 9 mean temp_A between 2018-02-03 and 2018-02-27 ...(其余数据略)
解决方案
你的核心需求是按分组计算时间区间的平均温度,避免循环的话,用dplyr的非等值连接是最直观高效的方案。下面是完整的实现步骤:
1. 准备温度数据
首先把两个分散的温度数据集合并,添加Place标识,统一结构,方便后续关联:
library(dplyr) library(lubridate) # 合并温度数据,标准化列名和结构 temp_combined <- bind_rows( data_A %>% mutate(Place = "PlaceA", temperature = temp_A), data_B %>% mutate(Place = "PlaceB", temperature = temp_B) ) %>% select(Place, t, temperature)
2. 为原数据生成时间区间
给df1按指定分组后,为每条记录(除了组内第一条)生成对应的时间区间(前一行的Time到当前行的Time):
df1_with_intervals <- df1 %>% group_by(Place, Group_Id, exprmt) %>% mutate( # 取前一行的日期作为区间起始点 interval_start = lag(Time), # 标记是否为组内第一条记录(后续用来设为NA) is_first_record = row_number() == 1 ) %>% ungroup()
3. 非等值连接计算区间平均温度
利用非等值连接匹配每个时间区间内的所有温度记录,计算平均值后合并回原数据:
final_result <- df1_with_intervals %>% # 先筛选出需要计算温度的非第一条记录 filter(!is_first_record) %>% # 按Place关联温度数据 left_join(temp_combined, by = "Place") %>% # 筛选时间落在[interval_start, Time)区间内的温度记录 # 注意:把日期转成带时间的格式,确保和温度数据的t列匹配 filter(t >= ymd_hms(paste(interval_start, "00:00:00")), t < ymd_hms(paste(Time, "00:00:00"))) %>% # 按原分组和当前行的Time分组,计算平均温度 group_by(Place, Group_Id, exprmt, Time, FollowUp) %>% summarise(avg_temp = mean(temperature, na.rm = TRUE), .groups = "drop") %>% # 合并回原数据集,补充第一条记录的NA值 right_join(df1_with_intervals, by = c("Place", "Group_Id", "exprmt", "Time", "FollowUp")) %>% # 把组内第一条记录的avg_temp设为NA,整理列顺序 mutate(avg_temp = ifelse(is_first_record, NA_real_, avg_temp)) %>% select(Place, Group_Id, Time, exprmt, FollowUp, avg_temp) %>% # 保持原数据的顺序不变 arrange(match(Time, df1$Time))
代码说明
- 非等值连接:这是实现需求的核心,它能高效地匹配每个时间区间内的所有小时级温度数据,完全避免手动循环。
- 时间格式统一:用
ymd_hms把原数据的日期转换成带时间的POSIXct格式,确保和温度数据的t列格式一致,避免时间匹配错误。 - NA处理:
na.rm = TRUE可以防止温度数据中存在NA值影响计算(如果你的数据没有NA可以去掉)。
验证结果
运行后final_result的结构和你预期的一致:
> head(final_result) Place Group_Id Time exprmt FollowUp avg_temp 1 PlaceA A1 2018-01-15 1 start NA 2 PlaceA A1 2018-02-03 1 week 5 14.923456 3 PlaceA A1 2018-02-27 1 week 9 16.789012 ...
内容的提问来源于stack exchange,提问作者Mata
相关产品推荐
相关产品推荐

