共计 2323 个字符,预计需要花费 6 分钟才能阅读完成。
背景介绍
CMIP6(第六次国际耦合模式比较计划)是当前气候研究最重要的数据来源之一,但原始数据分辨率各异(从 0.25°到 3°不等)。0.5×0.5 度分辨率作为气候分析的常用标准,具有三大优势:

- 兼容多数观测数据集(如 CRU、GPCP)
- 计算资源消耗适中
- 能保留关键气候特征
典型应用场景包括:多模型对比分析、降尺度研究输入、气候指标计算等。
工具链对比
常见重采样工具优劣势:
- CDO(Climate Data Operators)
- 优势:命令行操作高效,内置丰富插值算法
-
劣势:调试困难,复杂流程需多步中间文件
-
NCO(NetCDF Operators)
- 优势:轻量级,适合简单维度操作
-
劣势:缺乏高级插值方法
-
xarray+dask
- 优势:Python 生态整合好,支持懒加载和并行计算
- 劣势:学习曲线较陡
推荐组合:xarray 为主 + CDO 辅助验证
核心实现
环境准备
# 建议使用 conda 环境
conda create -n cmip6 python=3.8
conda install -c conda-forge xarray dask netCDF4 matplotlib cartopy
conda install -c conda-forge esmpy=8.3.0 # 必须≥8.0 才支持保守插值
数据读取与预处理
import xarray as xr
def load_cmip6_data(path):
# 使用 chunks 参数实现懒加载
ds = xr.open_dataset(path, chunks={'time': 12})
# 统一变量名(不同模型可能不同)if 'tas' in ds:
ds = ds.rename({'tas': 'temperature'})
# 处理缺失值
return ds.where(ds.temperature < 1e10)
重采样操作
方法一:双线性插值(推荐快速处理)
def bilinear_regrid(ds, target_res=0.5):
import xesmf as xe
# 创建目标网格
ds_out = xr.Dataset({'lat': (['lat'], np.arange(-90, 90, target_res)),
'lon': (['lon'], np.arange(0, 360, target_res))
})
# 创建 regridder(可重复使用)regridder = xe.Regridder(ds, ds_out, 'bilinear')
return regridder(ds.temperature)
方法二:保守插值(保持总量不变)
def conservative_regrid(ds):
# 需要安装 ESMPy
regridder = xe.Regridder(
ds,
ds_out,
'conservative_normed', # 归一化保守插值
weights=None
)
# 添加面积权重
ds['areacella'] = compute_grid_area(ds)
return regridder(ds.temperature)
质量评估
可视化对比
import matplotlib.pyplot as plt
def plot_comparison(orig, regrid):
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12,4))
orig.plot(ax=ax1, vmin=-20, vmax=30)
regrid.plot(ax=ax2, vmin=-20, vmax=30)
ax1.set_title(f'Original ({orig.shape})')
ax2.set_title(f'Regridded ({regrid.shape})')
统计指标验证
# 计算相对误差
def calc_error(high_res, low_res):
# 先将高分辨率数据聚合到目标分辨率
reference = high_res.coarsen(lat=round(0.5/high_res.lat.diff()[0].item()),
lon=round(0.5/high_res.lon.diff()[0].item()),
boundary='trim'
).mean()
return np.abs((low_res - reference)/reference)
避坑指南
- 缺失值处理
- CMIP6 常用 1e20 表示缺失值
-
建议在重采样前统一替换为 NaN:
ds = ds.where(ds.temperature < 1e10) -
内存优化
- 使用 dask 分块处理:
chunks={'time': 12} -
及时释放中间变量:
del temp_data -
并行加速
from dask.distributed import Client client = Client(threads_per_worker=1) # 避免 ESMPy 多线程冲突
延伸思考
插值方法影响
- 双线性插值:平滑结果但可能低估极端值
- 保守插值:保持总量但局部可能失真
- 建议气候极值分析用原始分辨率
扩展到其他分辨率
修改目标网格定义即可:
ds_out = xr.Dataset({'lat': (['lat'], np.arange(-90, 90, new_res)),
'lon': (['lon'], np.arange(0, 360, new_res))
})
学习资源
实践感受
在实际处理中,发现几个值得注意的点:保守插值虽然理论完美,但计算耗时是双线性的 3 - 5 倍;xarray 的 groupby 操作在重采样后执行效率更高;遇到内存问题时,优先考虑分时间步处理而非降低空间分辨率。建议首次处理时先用小区域测试(如isel(lat=slice(0,50))),确认效果后再全量运行。
正文完
发表至: 未分类
近三天内
