如何在分组DataFrame中用rle函数计算年度连续降温最长天数
问题描述
我有如下结构的DataFrame(df):
df <- data.frame(prox)
数据样例:
year month day Tmean <dbl> <dbl> <dbl> <dbl> 1 1956 1 1 13.5 2 1956 1 2 11.9 3 1956 1 3 9.71 4 1956 1 4 8.65 5 1956 1 5 4.51 6 1956 1 6 4.64 7 1956 1 7 6.66 8 1956 1 8 7.48 9 1956 1 9 5.56 10 1956 1 10 7.51
我需要找出连续降温天数的最大值。针对单一年份,已实现功能,代码如下(运行正常):
y <- rle(diff(df$Tmean) < 0) max(y$lengths[y$values], na.rm=TRUE) # [1] 6
但现在需要按年份(1956、1957……)分别计算该值,尝试用group_by时遇到问题:rle返回list类型,且当前代码未正确分组计算:
df %>% group_by(year) %>% summarise(x=list(rle(diff(df$Tmean) < 0)))
运行结果仅把全局rle结果按年份重复存储,并非分组计算:
year x <dbl> <list> 1 1956 <rle> 2 1957 <rle> 3 1958 <rle>
解决方法
你之前的代码核心问题是:group_by后使用df$Tmean会直接调用全局数据,而非当前分组的子集。下面提供两种可行的分组计算方案:
方案1:结合dplyr与rle直接计算
直接在分组的summarise块内完成rle分析和最大值提取,无需存储list对象:
library(dplyr) df %>% group_by(year) %>% summarise(max_consec_cooling = { # 计算当前年份内每日是否比前一天降温 cool_seq <- diff(Tmean) < 0 # 对降温序列做游程编码分析 rle_out <- rle(cool_seq) # 提取所有降温段的长度,取最大值(无降温时na.rm=TRUE会返回-Inf,可替换为0) max_len <- max(rle_out$lengths[rle_out$values], na.rm = TRUE) # 处理全年无降温的情况,将-Inf转为0 ifelse(is.infinite(max_len), 0, max_len) })
方案2:用窗口函数标记连续降温段(无需rle)
如果不想依赖rle,可以通过窗口函数给连续降温的天数分配分组ID,再统计每组长度的最大值:
library(dplyr) df %>% group_by(year) %>% mutate( # 判断当天是否比前一天降温(第一天无前置数据,标记为NA) is_cooling = Tmean < lag(Tmean), # 给连续降温的片段分配唯一ID:每当降温中断(或第一天),分组ID+1 cool_group = cumsum(!is_cooling | is.na(is_cooling)) ) %>% # 仅保留降温的天数 filter(is_cooling) %>% # 按年份和降温段分组,统计每个段的长度 group_by(year, cool_group) %>% summarise(segment_length = n()) %>% # 按年份取最大的降温段长度 group_by(year) %>% summarise(max_consec_cooling = max(segment_length, na.rm = TRUE)) %>% # 处理全年无降温的情况,将NA转为0 mutate(max_consec_cooling = ifelse(is.na(max_consec_cooling), 0, max_consec_cooling))
结果说明
两种方案都会返回按年份分组的最大连续降温天数,例如1956年的结果为6,与单年份计算结果一致。
内容的提问来源于stack exchange,提问作者nick
相关产品推荐
相关产品推荐

