
本文详解如何在存在大量 nan 值的二维规则经纬度网格上,对任意散点坐标(unstructured 2d coordinates)执行稳健的三次插值(cubic interpolation),绕过 `regulargridinterpolator` 对 nan 的严格限制,并推荐使用 `scipy.interpolate.griddata` 实现无缝、准确且可扩展的解决方案。
scipy.interpolate.RegularGridInterpolator 在 method='cubic' 模式下底层调用 B 样条拟合(make_interp_spline),该函数强制要求输入值数组中不能包含任何 NaN 或 inf —— 即使这些 NaN 仅位于数据边缘或稀疏无效区域,也会直接抛出 ValueError: Array must not contain infs or nans.。这与 method='linear' 的行为不同:线性插值通过分段线性外推+边界检查机制容忍局部 NaN(自动返回 fill_value 或引发可控错误),而三次插值需在整个维度上构建光滑样条,无法跳过缺失节点。
因此,当你的二维网格(如 20×50 的 lat0×lon0)含有约 40% 的 NaN 值时,不能直接将原始带 NaN 的 values 数组传入 RegularGridInterpolator(..., method='cubic')。你尝试的几种变通方式——如用 MaskedArray.compressed() 降维、改用 interp2d(其输出为笛卡尔积网格而非目标散点)、或手动剔除 NaN 后调用 interpn——均因维度不匹配或接口语义不符而失败。
✅ 正确解法是:放弃“规则网格插值器”的假设,转向“散点插值器”。scipy.interpolate.griddata 是专为此类场景设计的工具:它接受 (points, values) 形式的 非结构化 观测点集(即只提供有效数据点),并支持 'nearest'、'linear' 和 'cubic' 三种插值方法(后两者在 2D 中基于 Delaunay 三角剖分与分片多项式拟合)。
以下为针对你实际地理数据场景(经纬度网格 + 散点查询)的完整、鲁棒实现:
import numpy as np
from scipy.interpolate import griddata
# 假设你已有:
# lat0: (M,) 一维纬度向量(升序)
# lon0: (N,) 一维经度向量(升序)
# data_nan: (M, N) 二维网格数据,含大量 NaN
# lat, lon: (K,) 一维查询坐标数组(K 个散点,均在网格范围内)
# Step 1: 提取所有非 NaN 数据点的坐标和值
mask_valid = ~np.isnan(data_nan)
lat_flat = lat0[:, None] # (M, 1)
lon_flat = lon0[None, :] # (1, N)
lat_grid, lon_grid = np.broadcast_arrays(lat_flat, lon_flat) # (M, N)
# 展平并筛选有效点 → 得到长度为 P 的散点集(P ≈ 60% × M×N)
valid_lat = lat_grid[mask_valid].ravel() # (P,)
valid_lon = lon_grid[mask_valid].ravel() # (P,)
valid_data = data_nan[mask_valid].ravel() # (P,)
# Step 2: 对目标散点 (lat, lon) 执行 cubic 插值
# 注意:griddata 要求 query_points 形状为 (K, 2),故需堆叠
query_points = np.column_stack((lat, lon)) # (K, 2)
interped_cub = griddata(
points=(valid_lat, valid_lon), # 元组形式:(y_coords, x_coords)
values=valid_data,
xi=query_points,
method='cubic',
fill_value=np.nan # 显式指定:超出凸包范围时返回 NaN(与 RegularGridInterpolator 行为一致)
)
# ✅ interped_cub.shape == (K,) —— 完美匹配你的预期输出!⚠️ 关键注意事项:
- griddata 的 points 参数接受元组 (y, x),对应 lat(垂直方向)、lon(水平方向),顺序必须与你的网格定义一致;
- 'cubic' 方法在 2D 中要求至少 16 个邻近点才能稳定拟合,若某查询点周围有效样本过少(如靠近大片 NaN 区域),结果可能失真或返回 fill_value;此时可结合 method='linear' 回退策略(见下方增强版);
- 性能提示:对数千至数万查询点,griddata 效率良好;若需高频调用,建议预构建 LinearNDInterpolator 或 CloughTocher2DInterpolator 实例复用。
? 进阶健壮性增强(推荐用于生产):
from scipy.interpolate import LinearNDInterpolator, CloughTocher2DInterpolator
# 首选:CloughTocher2DInterpolator(显式 cubic,比 griddata 更可控)
try:
interp_cubic = CloughTocher2DInterpolator(
np.column_stack((valid_lat, valid_lon)), valid_data,
fill_value=np.nan
)
interped_cub = interp_cubic(np.column_stack((lat, lon)))
except Exception as e:
print(f"Cubic failed, falling back to linear: {e}")
interp_linear = LinearNDInterpolator(
np.column_stack((valid_lat, valid_lon)), valid_data,
fill_value=np.nan
)
interped_cub = interp_linear(np.column_stack((lat, lon)))总结:面对含 NaN 的规则网格插值需求,RegularGridInterpolator 的 'cubic' 模式并非适用工具;应主动转换范式,利用 griddata 或 CloughTocher2DInterpolator 等基于散点的插值器,它们天然支持稀疏、不规则观测,并能精确返回与查询点一一对应的 cubic 插值结果,同时保持对无效区域的合理处理(如返回 NaN)。这一方法已在气象、海洋等高缺失率网格数据业务中被广泛验证。









