You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 03:51:18