如何使用dplyr实现分阈值的寒潮与强寒潮判定逻辑
dplyr 寒潮等级判定实现方案
核心逻辑是先计算实际气温与常年均值的差值,再用dplyr::case_when()按规则分场景判定等级,比嵌套ifelse逻辑更清晰易维护。
首先修正原有常年均值计算的小问题:原代码中按日分组后对所有列求均值,会导致日期列Date被无意义平均,调整后完整实现代码如下:
library(tidyverse) library(zoo) set.seed(123) df <- data.frame("Date"= seq(from = as.Date("1970-1-1"), to = as.Date("2000-12-31"), by = "day"), "Station1" = runif(length(seq.Date(as.Date("1970-1-1"), as.Date("2000-12-31"), "days")), 10, 30), "Station2" = runif(length(seq.Date(as.Date("1970-1-1"), as.Date("2000-12-31"), "days")), 11, 29), "Station3" = runif(length(seq.Date(as.Date("1970-1-1"), as.Date("2000-12-31"), "days")), 8, 28)) # 计算常年最低气温(按儒略日分组统计各站点多年均值) df_summarise_all <- df %>% as_tibble() %>% mutate(day = format(Date, format='%m-%d')) %>% select(-Date) %>% # 移除不需要求平均的日期列 group_by(day) %>% summarise(across(everything(), mean, na.rm = TRUE)) %>% # 仅对站点列求均值 pivot_longer(cols = -day, names_to = "Stations", values_to = "mean_MinT") # 识别寒潮等级 df_out <- df %>% as_tibble() %>% mutate(day = format(Date, format='%m-%d')) %>% pivot_longer(cols = -c(Date, day), names_to = "Stations", values_to = "MinT") %>% left_join(df_summarise_all, by = c("day", "Stations")) %>% # 计算气温距平:实际气温 - 常年同期均值 mutate(temp_delta = MinT - mean_MinT, # 按规则判定寒潮等级 coldwave_level = case_when( # 常年最低温≥10℃的场景 mean_MinT >= 10 & temp_delta <= -7 ~ "强寒潮", mean_MinT >= 10 & temp_delta <= -5 & temp_delta >= -6 ~ "寒潮", # 常年最低温<10℃的场景 mean_MinT < 10 & temp_delta <= -6 ~ "强寒潮", mean_MinT < 10 & temp_delta <= -4 & temp_delta >= -5 ~ "寒潮", # 其余情况归为无寒潮 TRUE ~ NA_character_ ), # 如需单独的逻辑判定列可额外生成 is_coldwave = !is.na(coldwave_level), is_strong_coldwave = coldwave_level == "强寒潮" )
关键说明
case_when()按优先级匹配条件,符合第一个满足的条件就返回对应值,不用写多层嵌套判断- 先计算距平
temp_delta可以避免重复计算,代码可读性更高 - 如果你需要判断连续多日降温的寒潮规则,只需要调整
zoo::rollapplyr的宽度参数即可,当前单日判定无需用到滑动窗口函数
内容的提问来源于stack exchange,提问作者UseR10085
相关产品推荐
相关产品推荐

