如何在R中按ID分组,基于Threshold划分多组并计算平均浓度?
解决方案
高效分组逻辑(无需额外关联操作)
可以直接利用dplyr的分组窗口函数实现三组划分,避免原代码中低效的left_join操作,同时覆盖所有边界情况(比如部分ID没有Threshold=1或Threshold=2的场景):
library(dplyr) # 第一步:生成group列 df_processed <- df1 %>% arrange(ID, DateTime) %>% # 确保每个ID内数据按时间顺序排列 group_by(ID) %>% mutate( # 提取当前ID中首次出现Threshold=1和2的时间点 first_thresh1 = min(ifelse(Threshold == 1, DateTime, NA), na.rm = TRUE), first_thresh2 = min(ifelse(Threshold == 2, DateTime, NA), na.rm = TRUE), # 根据时间区间判断所属分组 group = case_when( # 无Threshold=1的ID,全部归为group1 is.na(first_thresh1) ~ "group 1", # Threshold=1之前的行 DateTime < first_thresh1 ~ "group 1", # 有Threshold=1但无Threshold=2的ID,后续行归为group2 is.na(first_thresh2) ~ "group 2", # Threshold=1到Threshold=2之间的行 DateTime < first_thresh2 ~ "group 2", # Threshold=2之后到当前ID结束的行 TRUE ~ "group 3" ) ) %>% ungroup()
结合Time_difference的分组调整
如果需要处理Time_difference>600时拆分分组(且每个ID最多3组),可以在上述逻辑基础上增加拆分标记,确保分组不超过3组:
df_processed <- df1 %>% arrange(ID, DateTime) %>% group_by(ID) %>% mutate( # 先基于Threshold确定基础分组 base_group = case_when( cumsum(Threshold == 1) == 0 ~ 1, cumsum(Threshold == 2) == 0 ~ 2, TRUE ~ 3 ), # 标记Time_difference超过600的拆分点 split_trigger = ifelse(Time_difference > 600, 1, 0), # 累积拆分次数,确保最终分组不超过3 final_group_num = pmin(base_group + cumsum(split_trigger), 3), group = paste0("group ", final_group_num) ) %>% ungroup() %>% select(-base_group, -split_trigger, -final_group_num) # 清理中间变量
计算平均浓度
完成分组后,直接按ID和group聚合计算平均浓度:
avg_concentration <- df_processed %>% group_by(ID, group) %>% summarise( average_concentration = mean(Concentration, na.rm = TRUE), .groups = "drop" )
注意事项
- 确保数据中
DateTime列是时间类型(可通过as.POSIXct()转换),否则时间比较会出错 - R是大小写敏感的,注意代码中变量名和你的数据集列名一致(比如原代码中你混用了
Threshold和threshold,需统一)
内容的提问来源于stack exchange,提问作者bre123
相关产品推荐
相关产品推荐

