如何计算河流温度时序中阈值上下的首次及持续达标日序?
问题与解决方案
问题需求
我有一个存储两条河流两年日温度时间序列的dataframe,需要针对每条河流和每一年,计算四个关键日序(doy,1月1日为1,12月31日为365):
- 温度首次≥15℃的日序
- 温度持续≥15℃的起始日序(持续指直到秋季不再出现低于15℃的情况)
- 温度首次≤15℃的日序
- 温度持续≤15℃的起始日序(持续指直到次年春季不再出现高于15℃的情况)
示例数据获取与预处理
以下是获取并预处理USGS水温数据的代码:
library(ggplot2) library(lubridate) library(dplyr) library(dataRetrieval) siteNumber <- c("01428500","01432805") # 美国地质调查局站点编号 parameterCd <- "00010" # 水温参数编码 statCd <- "00003" # 均值统计编码 startDate <- "2018-01-01" endDate <- "2019-10-31" dat <- readNWISdv(siteNumber, parameterCd, startDate, endDate, statCd=statCd) # 从USGS获取时间序列数据 dat <- dat[,c(2:4)] colnames(dat)[3] <- "temperature" # 可视化时间序列 ggplot(data = dat, aes(x = Date, y = temperature)) + geom_point() + theme_bw() + facet_wrap(~site_no) # 添加年份和日序列(doy;1月1日=1,12月31日=365) dat <- dat %>% mutate(year = year(Date), doy = yday(Date))
无效尝试代码
我曾尝试用filter()函数筛选,但无法得到目标结果:
dat %>% group_by(site_no,year) %>% filter(temperature >= 15 & temperature <= 15)
理想输出格式
期望得到如下结构的结果:
site_no year doy_firstabove15 doy_sustainedAbove15 doy_firstbelow15 doy_sustainedBelow15 1 01428500 2018 136 144 253 286 2 01428500 2019 140 146 279 289 3 01432805 2018 143 143 272 276 4 01432805 2019 140 140 278 278
解决方案代码
使用dplyr分组后结合逻辑筛选,可实现目标计算:
dat_result <- dat %>% group_by(site_no, year) %>% arrange(doy) %>% # 确保数据按日序升序排列 mutate( above15 = temperature >= 15, # 标记温度≥15的日期 below15 = temperature <= 15 # 标记温度≤15的日期 ) %>% summarise( # 1. 当年首次温度≥15℃的日序 doy_firstabove15 = first(doy[above15]), # 2. 持续≥15℃的起始日序:最后一次低温后的首个高温日(之后无低温) doy_sustainedAbove15 = { last_low_doy <- max(doy[!above15], na.rm = TRUE) if (is.infinite(last_low_doy)) first(doy) else first(doy[doy > last_low_doy & above15]) }, # 3. 当年首次温度≤15℃的日序(秋季降温首个达标日) doy_firstbelow15 = { last_high_doy <- max(doy[above15], na.rm = TRUE) if (is.infinite(last_high_doy)) first(doy) else first(doy[doy > last_high_doy & below15]) }, # 4. 持续≤15℃的起始日序:最后一次高温后的首个低温日(之后无高温) doy_sustainedBelow15 = { last_high_doy <- max(doy[above15], na.rm = TRUE) if (is.infinite(last_high_doy)) first(doy) else first(doy[doy > last_high_doy & below15]) } ) %>% ungroup() # 输出结果 print(dat_result)
代码逻辑说明
- 先按站点和年份分组,确保数据按日序排序,保证时间顺序正确
- 用
above15和below15标记温度达标情况,简化后续筛选 doy_firstabove15直接取首个高温日的doydoy_sustainedAbove15:找到当年最后一次低温日,取之后首个高温日,即为持续高温的起点doy_firstbelow15和doy_sustainedBelow15:找到当年最后一次高温日,取之后首个低温日,分别对应秋季首次降温日和持续低温的起点
内容的提问来源于stack exchange,提问作者tassones
相关产品推荐
相关产品推荐

