网格化降水数据60个月滑动窗口阈值超次数计算求助
优化滑动窗口降水频次统计的方案
先说说你原代码的核心问题:
- 你在循环里计算了
aa,但没有把计算结果添加到列表a中,所以最后得到空列表是必然的; - 手动嵌套遍历经纬度维度完全没必要,72*144=10368次循环既低效又容易出错,xarray本身支持直接对多维数据做向量化操作,能一步处理所有空间维度;
- 原代码里的阈值写的是
<-50,和你描述的“低于5”不符,这里要注意修正。
最优方案:用xarray向量化操作直接处理
既然你的数据是xarray的DataArray(从.where()和.rolling()方法能判断出来),完全可以利用xarray的广播和维度特性,一步完成滑动窗口统计,代码简洁且效率极高:
# 假设AS是xarray.DataArray,维度为(time, lat, lon) = (324,72,144) # 1. 生成布尔掩码:标记所有降水低于5的时刻 precip_below_5 = AS < 5 # 2. 在time维度上做60步滑动窗口,统计窗口内低于5的次数 # - min_periods=60:只保留有完整60个月数据的窗口(前59个时间步会返回NaN) # - skipna=False:如果窗口内有缺失值,不忽略(可根据你的数据实际情况调整) rolling_counts = precip_below_5.rolling(time=60, min_periods=60).sum(skipna=False) # 验证结果形状,和原始数据维度一致:(324,72,144) print(rolling_counts.shape)
这里的原理很简单:布尔值True会被当作1,False当作0,.sum()就直接统计出了窗口内降水低于5的月份数。如果你的数据存在缺失值,可以调整skipna参数;如果允许统计不完整的窗口(比如前59个时间步用当前已有的月份数计算),去掉min_periods=60即可。
若必须用循环(不推荐)
如果因为特殊需求一定要用循环,那修正原代码,把每个格点的计算结果存入列表后再合并成三维数组:
import xarray as xr result_list = [] for lon_idx in range(len(AS.lon)): for lat_idx in range(len(AS.lat)): # 修正阈值为<5,计算当前格点的滑动统计 grid_counts = AS[:, lat_idx, lon_idx].where(AS[:, lat_idx, lon_idx] < 5).rolling(time=60).count() result_list.append(grid_counts) # 将一维结果合并为三维数组,还原原维度顺序 final_result = xr.concat(result_list, dim=AS.lat).transpose('time', 'lat', 'lon') print(final_result.shape)
但还是强烈推荐第一种向量化方案,不仅代码量少,运行速度更是比循环快几个数量级,尤其是处理大尺寸网格数据时优势明显。
内容的提问来源于stack exchange,提问作者user11036847
相关产品推荐
相关产品推荐

