RegularGridInterpolator远慢于已弃用的interp2d,如何优化?
你的代码确实存在测试场景不对等的问题
你当前的测试用例里,interp2d的f(x, y)走了特殊优化路径——当输入的插值点就是原始网格点时,它直接返回原始数据的副本(甚至可能是引用),根本没执行插值计算,这才让它看起来速度极快。而RegularGridInterpolator的f2(M)是真的在对每个点做插值运算,两者的测试场景完全不公平,结果没有参考性。
另外,你生成M的方式也完全没必要:np.meshgrid+np.stack会创建一个9000×9000×2的巨型数组,既浪费内存,又额外增加了数据传递的开销。
正确的性能对比方式
要公平对比两者的性能,得用非原始网格的插值点测试,同时优化RegularGridInterpolator的调用逻辑:
import numpy as np from scipy.interpolate import interp2d, RegularGridInterpolator # 先缩小数据规模测试(9000×9000太占内存,不利于快速验证) x = np.arange(1000) y = np.arange(1000) z = np.random.randint(-1000, high=1000, size=(1000, 1000)) f = interp2d(x, y, z, kind='linear', copy=False) f2 = RegularGridInterpolator((x, y), z, method="linear") # 生成随机插值点(完全脱离原始网格) test_points = np.random.rand(100000, 2) * (x.max(), y.max()) # 测试interp2d:需要拆分点的x、y分量 %timeit f(test_points[:,0], test_points[:,1]) # 测试RegularGridInterpolator:直接传入点数组即可,无需预处理 %timeit f2(test_points)
实际测试会发现,RegularGridInterpolator在处理随机插值点时的性能反而优于interp2d,这才符合官方推荐它作为替代方案的定位。
提升插值速度的实用方案
避免不必要的内存开销
不要手动生成巨型网格点数组,直接利用numpy的广播特性传递坐标,比如用f2((x_new[:, None], y_new[None, :]))生成网格插值结果,省去中间数组的创建;同时给RegularGridInterpolator传入bounds_error=False, fill_value=None(如果允许外插),减少边界检查的额外开销。分块处理大规模数据
9000×9000的数组本身占用约648MB内存(int32类型),如果不需要全局插值,可以分块处理数据,降低单块的内存压力,提升CPU缓存命中率。选择更高效的实现
规则网格的线性插值可以用scipy.interpolate.RectBivariateSpline,性能和RegularGridInterpolator接近但接口更灵活;也可以用numba对插值逻辑做JIT编译,自定义线性插值函数,大规模数据下能获得明显提速。优化数据类型
如果精度允许,把z的类型从int32改成float32,能减少内存占用,提升计算速度。
内容的提问来源于stack exchange,提问作者HerpDerpington

