使用Xarray对流域NetCDF文件求和时的NaN值处理问题
解决流域降水统计中保留流域外NaN的问题
问题核心:skipna=True会跳过所有NaN值进行统计计算,流域外的网格点全为NaN,求和后直接变成0。要实现流域内忽略NaN计算、流域外保留NaN,可以通过标记流域外区域的方式处理。
解决步骤
- 先将原数据中的无效值(-9999)转为标准NaN,避免后续计算干扰
- 裁剪得到流域范围的降水数据
- 生成流域外掩码:识别所有时间步都为NaN的网格点(即流域外区域)
- 执行月尺度统计计算(求和/均值/方差等)
- 用掩码将统计结果中流域外的0值还原为NaN
修改后的代码
import geopandas as gpd import rioxarray import xarray as xr import matplotlib.pyplot as plt from shapely.geometry import mapping # 加载shapefile shapefile_path = "my_shapefile.shp" shapefile = gpd.read_file(shapefile_path, crs="epsg:4326") # 加载NetCDF文件并转换无效值为NaN netcdf_path = "my_netcdffile.nc" ds = xr.open_dataset(netcdf_path) pre = ds["pre"].where(ds["pre"] != -9999) # 把原数据中的-9999替换成标准NaN # 裁剪操作 pre.rio.set_spatial_dims(x_dim="lon", y_dim="lat", inplace=True) pre.rio.write_crs("epsg:4326", inplace=True) basin = pre.rio.clip( shapefile.geometry.apply(mapping), pre.rio.crs ) # 生成流域外掩码:所有时间步都是NaN的网格点标记为True basin_out_mask = basin.isnull().all(dim="time") # 执行月尺度求和(忽略流域内的NaN) sum_data = basin.resample({"time": "month"}).sum(keep_attrs=True, skipna=True) # 将流域外的0值还原为NaN sum_data = sum_data.where(~basin_out_mask) # 若需计算均值、方差,同理处理 # mean_data = basin.resample({"time": "month"}).mean(keep_attrs=True, skipna=True).where(~basin_out_mask) # var_data = basin.resample({"time": "month"}).var(keep_attrs=True, skipna=True).where(~basin_out_mask)
原理说明
basin.isnull().all(dim="time"):遍历每个网格点的所有时间步,只有全时间步都是NaN的点才会被标记为流域外区域;只要有一个时间步存在有效值,就判定为流域内区域。sum_data.where(~basin_out_mask):将掩码标记为True的流域外区域数值替换为NaN,同时保留流域内的统计计算结果。
内容的提问来源于stack exchange,提问作者jei L
相关产品推荐
相关产品推荐

