散点数据插值(griddata
)#
假设你有多维数据,例如,对于一个底层函数 \(f(x, y)\),你只知道在点 (x[i], y[i])
处的值,而这些点并不形成一个规则的网格。
假设我们想要插值一个2维函数
>>> import numpy as np
>>> def func(x, y):
... return x*(1-x)*np.cos(4*np.pi*x) * np.sin(4*np.pi*y**2)**2
在一个 [0, 1]x[0, 1] 的网格上
>>> grid_x, grid_y = np.meshgrid(np.linspace(0, 1, 100),
... np.linspace(0, 1, 200), indexing='ij')
但我们只知道它在1000个数据点处的值:
>>> rng = np.random.default_rng()
>>> points = rng.random((1000, 2))
>>> values = func(points[:,0], points[:,1])
这可以使用 griddata
来完成——下面,我们尝试所有的插值方法:
>>> from scipy.interpolate import griddata
>>> grid_z0 = griddata(points, values, (grid_x, grid_y), method='nearest')
>>> grid_z1 = griddata(points, values, (grid_x, grid_y), method='linear')
>>> grid_z2 = griddata(points, values, (grid_x, grid_y), method='cubic')
可以看到,所有方法都在某种程度上重现了精确结果,但对于这个平滑函数,分段三次插值给出了最好的结果(黑色点显示被插值的数据):
>>> import matplotlib.pyplot as plt
>>> plt.subplot(221)
>>> plt.imshow(func(grid_x, grid_y).T, extent=(0, 1, 0, 1), origin='lower')
>>> plt.plot(points[:, 0], points[:, 1], 'k.', ms=1) # 数据
>>> plt.title('原始')
>>> plt.subplot(222)
>>> plt.imshow(grid_z0.T, extent=(0, 1, 0, 1), origin='lower')
>>> plt.title('最近邻')
>>> plt.subplot(223)
>>> plt.imshow(grid_z1.T, extent=(0, 1, 0, 1), origin='lower')
>>> plt.title('Linear')
>>> plt.subplot(224)
>>> plt.imshow(grid_z2.T, extent=(0, 1, 0, 1), origin='lower')
>>> plt.title('Cubic')
>>> plt.gcf().set_size_inches(6, 6)
>>> plt.show()
对于每种插值方法,此函数委托给相应的类对象——这些类也可以直接使用——
NearestNDInterpolator
、LinearNDInterpolator
和 CloughTocher2DInterpolator
用于二维分段三次插值。
所有这些插值方法都依赖于使用 scipy.spatial
中包装的 QHull
库对数据进行三角剖分。
注意
griddata
基于三角剖分,因此适用于非结构化、分散的数据。如果你的数据在完整网格上,
griddata
函数——尽管其名称如此——并不是合适的工具。请改用 RegularGridInterpolator
。
注意
如果输入数据使得输入维度具有不可比拟的单位并且相差许多数量级,插值函数可能会有数值伪影。
考虑在插值前重新缩放数据,或者使用 griddata
的 rescale=True
关键字参数。
使用径向基函数进行平滑/插值#
径向基函数可用于在 N 维中平滑/插值分散数据,但应谨慎用于超出观测数据范围的外推。
1-D 示例#
此示例比较了 scipy.interpolate
模块中的 RBFInterpolator
和 UnivariateSpline
类的使用。
>>> import numpy as np
>>> from scipy.interpolate import RBFInterpolator, InterpolatedUnivariateSpline
>>> import matplotlib.pyplot as plt
>>> # 设置数据
>>> x = np.linspace(0, 10, 9).reshape(-1, 1)
>>> y = np.sin(x)
>>> xi = np.linspace(0, 10, 101).reshape(-1, 1)
>>> # 使用 fitpack2 方法
>>> ius = InterpolatedUnivariateSpline(x, y)
>>> yi = ius(xi)
>>> fix, (ax1, ax2) = plt.subplots(2, 1)
>>> ax1.plot(x, y, 'bo')
>>> ax1.plot(xi, yi, 'g')
>>> ax1.plot(xi, np.sin(xi), 'r')
>>> ax1.set_title('使用单变量样条插值')
>>> # 使用 RBF 方法
>>> rbf = RBFInterpolator(x, y)
>>> fi = rbf(xi)
>>> ax2.plot(x, y, 'bo')
>>> ax2.plot(xi, fi, 'g')
>>> ax2.plot(xi, np.sin(xi), 'r')
>>> ax2.set_title('使用 RBF - 多二次插值')
>>> plt.tight_layout()
>>> plt.show()
二维示例#
本示例展示了如何插值散乱的二维数据:
>>> import numpy as np
>>> from scipy.interpolate import RBFInterpolator
>>> import matplotlib.pyplot as plt
>>> # 二维测试 - 设置散乱数据
>>> rng = np.random.default_rng()
>>> xy = rng.random((100, 2))*4.0-2.0
>>> z = xy[:, 0]*np.exp(-xy[:, 0]**2-xy[:, 1]**2)
>>> edges = np.linspace(-2.0, 2.0, 101)
>>> centers = edges[:-1] + np.diff(edges[:2])[0] / 2.
>>> x_i, y_i = np.meshgrid(centers, centers)
>>> x_i = x_i.reshape(-1, 1)
>>> y_i = y_i.reshape(-1, 1)
>>> xy_i = np.concatenate([x_i, y_i], axis=1)
>>> # 使用 RBF
>>> rbf = RBFInterpolator(xy, z, epsilon=2)
>>> z_i = rbf(xy_i)
>>> # 绘制结果
>>> fig, ax = plt.subplots()
>>> X_edges, Y_edges = np.meshgrid(edges, edges)
>>> lims = dict(cmap='RdBu_r', vmin=-0.4, vmax=0.4)
>>> mapping = ax.pcolormesh(
... X_edges, Y_edges, z_i.reshape(100, 100),
... shading='flat', **lims
... )
>>> ax.scatter(xy[:, 0], xy[:, 1], 100, z, edgecolor='w', lw=0.1, **lims)
>>> ax.set(
… title=’RBF插值 - 多二次型’, … xlim=(-2, 2), … ylim=(-2, 2), … ) >>> fig.colorbar(mapping)