如何基于峰值优化确定臭氧峰值季的最佳连续6个月时段?
实现WHO臭氧AQG峰值季定义的后续解决思路
一、先标准化时间序列与滑动均值计算
首先确保你的tibble数据集的日期列是Date类型,然后严格贴合WHO定义:计算每个候选连续6个月时段内的日最大8小时平均臭氧浓度的均值——这比单纯依赖findpeaks的单点峰值更准确,因为峰值季的核心是6个月的整体平均水平。
- NA值处理:计算均值时用
na.rm = TRUE,但需添加过滤规则:如果时段内有效数据占比低于75%(可根据WHO官方标准调整),直接标记为无效窗口,避免异常值干扰结果。 - 两种窗口计算方式:
- 自然月分组:适合严格按“连续6个自然月”定义的场景,先按月聚合日均值,再计算连续6个月的滑动均值。
- 连续天数滑动:如果WHO定义是“连续180天左右”,则用基于日期的滑动窗口计算。
二、分区域处理候选窗口
北半球(峰值季在单年内)
北半球臭氧峰值集中在夏季,所有候选窗口均在单年内:
- 遍历每年的7种连续6个月组合(1-6月、2-7月……7-12月)。
- 对每个组合,筛选对应时段的数据,计算日最大8小时臭氧的均值,过滤无效窗口后,取均值最高的时段作为该年峰值季。
- 可借助
findpeaks结果缩小范围:提取年度峰值对应的月份,只遍历包含该月份的候选窗口,减少计算量。
南半球(峰值季跨两年)
南半球臭氧峰值多在春季,候选窗口会跨两个年份(比如上年10月-当年3月):
- 将相邻两年的数据合并(比如2023年7月-2024年6月),生成跨年度时间序列。
- 遍历6种跨年度的连续6个月组合(上年7月-当年1月……上年12月-当年5月)。
- 同样计算每个窗口的均值,过滤无效窗口后取最大值对应的时段。
三、结合findpeaks优化筛选
你之前用pracma::findpeaks识别的峰值点可以用来缩小候选窗口范围:
- 提取
findpeaks输出中峰值对应的月份,只保留包含该月份的连续6个月窗口,无需遍历所有可能的组合。 - 例如:如果
findpeaks显示每年8月是臭氧峰值月,北半球只需考虑3-8月、4-9月、5-10月、6-11月、7-12月这5个窗口,减少计算量。
四、关键代码片段示例
1. 按月聚合与滑动均值计算(用tidyverse+slider)
library(tidyverse) library(slider) # 假设数据集:ozone_data,列包含date(Date)、daily_max_8h_ozone ozone_data <- ozone_data %>% arrange(date) # 按月聚合日最大8小时臭氧的月均值,并过滤有效数据不足的月份 monthly_ozone <- ozone_data %>% mutate(month_year = floor_date(date, "month")) %>% group_by(month_year) %>% summarise( monthly_mean = mean(daily_max_8h_ozone, na.rm = TRUE), valid_days = sum(!is.na(daily_max_8h_ozone)), total_days = n() ) %>% ungroup() %>% filter(valid_days / total_days >= 0.75) # 计算连续6个月的滑动均值(仅保留完整窗口) monthly_ozone <- monthly_ozone %>% mutate( rolling_6month_mean = slide_dbl( monthly_mean, ~mean(.x), .before = 5, .complete = TRUE ) )
2. 北半球峰值季筛选
northern_peak_seasons <- monthly_ozone %>% mutate(year = year(month_year)) %>% group_by(year) %>% filter(!is.na(rolling_6month_mean)) %>% # 取每年均值最高的窗口 slice_max(rolling_6month_mean, n = 1) %>% mutate( peak_season_start = month_year - months(5), peak_season_end = month_year ) %>% select(year, peak_season_start, peak_season_end, rolling_6month_mean)
3. 南半球跨年度峰值季筛选
southern_peak_seasons <- monthly_ozone %>% # 标记跨年度分组(上年7月-当年6月为一组) mutate( cross_year = ifelse( month(month_year) >= 7, paste(year(month_year), year(month_year)+1, sep = "-"), paste(year(month_year)-1, year(month_year), sep = "-") ) ) %>% group_by(cross_year) %>% # 确保每组有完整的12个月数据 filter(n() == 12) %>% filter(!is.na(rolling_6month_mean)) %>% slice_max(rolling_6month_mean, n = 1) %>% mutate( peak_season_start = month_year - months(5), peak_season_end = month_year ) %>% select(cross_year, peak_season_start, peak_season_end, rolling_6month_mean)
五、验证与调整
- 核对结果:北半球峰值季应集中在4-9月左右,南半球应集中在10月-次年3月左右,符合气象规律。
- 调整NA阈值:如果WHO有明确的缺失数据标准,替换75%的阈值为官方要求。
- 窗口定义:如果WHO的“连续6个月”是指连续180天而非自然月,改用
slide_index_dbl按日期计算滑动均值,示例:
ozone_data <- ozone_data %>% mutate( rolling_6month_mean = slide_index_dbl( daily_max_8h_ozone, date, ~mean(.x, na.rm = TRUE), .before = days(179), .complete = TRUE ) )
内容的提问来源于stack exchange,提问作者lcsmmn
相关产品推荐
相关产品推荐

