
3.7.2 多维插值
使用interp2d( )可以进行二维插值运算。它的调用形式如下:
interp2d(x, y, z, kind='linear', ...)
其中x、y、z都是一维数组,如果传入的是多维数组,则先将其转为一维数组。kind参数指定插值运算的阶数,可以为'linear'、'cubic'、'quintic'。
下面的例子对某个函数曲面上的网格点进行二维插值,效果如图3-43所示。其中下左图显示插值之前的数据,而下右图显示插值运算后得到的结果。

图3-43 使用interp2d类进行二维插值
def func(x, y): ❶ return (x+y)* np.exp(-5.0* (x** 2 + y** 2)) # X-Y轴分为15* 15的网格 y, x = np.mgrid[-1:1:15j, -1:1:15j] ❷ fvals = func(x, y) # 计算每个网格点上的函数值 # 二维插值 newfunc = interpolate.interp2d(x, y, fvals, kind='cubic') ❸ # 计算100* 100的网格上的插值 xnew = np.linspace(-1,1,100) ynew = np.linspace(-1,1,100) fnew = newfunc(xnew, ynew) ❹
❶func是计算曲面上各点高度的函数。❷计算X、Y轴在-1到1范围之内,大小为15×15的等间距网格上各点的高度。注意所得到的二维数组fvals的第0轴与Y轴对应,第一轴与X轴对应。❸使用网格上各点的X、Y和Z轴的坐标创建interp2d对象,这里我们使用二阶插值曲面。❹interp2d对象可以像函数一样调用,我们用它计算插值曲面在一个更密网格中的高度值。注意这里的参数是两个一维数组,分别指定网格的X-Y轴坐标,而不需要通过mgrid创建网格坐标数组。
1.griddata
interp2d类只能对网格形状的取样值进行插值运算,如果需要对随机散列的取样点进行插值,则可以使用griddata( )。其调用形式如下:
griddata(points, values, xi, method='linear', fill_value=nan)
其中points表示K维空间中的坐标,它可以是形状为(N, k)的数组,也可以是一个有k个数组的序列,N为数据的点数。values是points中每个点对应的值。xi是需要进行插值运算的坐标,其形状为(M, k)。method有三个选项——'nearest'、'linear'、'cubic',分别对应0阶、1阶以及3阶插值。
下面是griddata( )的演示程序,其输出如图3-44所示。下左图与'nearest'算法对应,平面上每个点都被填充为与它最近的采样点的数据,因此图中由许多相同颜色的色块构成。'linear'和'cubic'算法只对采样点构成的凸包区域进行插值,区域之外采用fill_value进行填充。中图和下右图中的白色区域为插值的凸包区域之外。

图3-44 使用gridata进行二维插值
griddata( )使用欧几里得距离计算插值。如果K维空间中每个维度的取值范围相差较大,则应先将数据正规化,然后使用griddata( )进行插值运算。
# 计算随机N个点的坐标,以及这些点对应的函数值 N = 200 np.random.seed(42) x = np.random.uniform(-1, 1, N) y = np.random.uniform(-1, 1, N) z = func(x, y) yg, xg = np.mgrid[-1:1:100j, -1:1:100j] xi = np.c_[xg.ravel( ), yg.ravel( )] methods = 'nearest', 'linear', 'cubic' zgs = [interpolate.griddata((x, y), z, xi, method=method).reshape(100, 100) for method in methods]
2.径向基函数插值
径向基函数(radial basis function)插值算法也可以用于高维随机散布点的插值。所谓径向基函数,是指函数值只与某特定点的距离相关的一类函数,其中xi是某个给定取样点的坐标。使用这些ϕ函数,可以近似表示N维空间中的函数:

为了方便读者理解RBF,下面先看一个一维插值的例子,结果如图3-45所示。图中显示了三种ϕ函数对应的插值曲线:multiquadric、gaussian和linear。

图3-45 一维RBF插值
from scipy.interpolate import Rbf x1 = np.array([-1, 0, 2.0, 1.0]) y1 = np.array([1.0, 0.3, -0.5, 0.8]) funcs = ['multiquadric', 'gaussian', 'linear'] nx = np.linspace(-3, 4, 100) rbfs = [Rbf(x1, y1, function=fname) for fname in funcs] ❶ rbf_ys = [rbf(nx) for rbf in rbfs] ❷
❶使用表示取样点的x和y数组创建一个rbf对象,并通过function参数指定所使用的径向基函数。❷rbf对象可以像函数一样被调用,我们用它计算以nx为横坐标对应的插值曲线的值。
rbf对象的nodes属性保存wi系数:
for fname, rbf in zip(funcs, rbfs): print fname, rbf.nodes multiquadric [ -3.79570791 9.82703701 5.08190777 -11.13103777] gaussian [ 1.78016841 -1.83986382 -1.69565607 2.5266374 ] linear [-0.26666667 0.6 0.73333333 -0.9 ]
下面的程序演示二维径向基函数插值,效果如图3-46所示。

图3-46 二维径向基函数插值
rbfs = [Rbf(x, y, z, function=fname) for fname in funcs] rbf_zg = [rbf(xg, yg).reshape(xg.shape) for rbf in rbfs]
某些径向基函数可以通过epsilon参数指定其作用范围,该值越大每个插值点的作用范围越广,所得到的曲面也就越平滑。下面的代码演示gaussian径向基函数的epsilon参数与插值结果的关系,效果如图3-47所示。
epsilons = 0.1, 0.15, 0.3 rbfs = [Rbf(x, y, z, function="gaussian", epsilon=eps) for eps in epsilons] zgs = [rbf(xg, yg).reshape(xg.shape) for rbf in rbfs]