这与定义 here 的解决方案相同,但应用于某些功能并与 Scipy 中可用的 interp2d 进行比较。我们使用 numba 库使插值函数比 Scipy 实现更快。
import numpy as np
from scipy.interpolate import interp2d
import matplotlib.pyplot as plt
from numba import jit, prange
@jit(nopython=True, fastmath=True, nogil=True, cache=True, parallel=True)
def bilinear_interpolation(x_in, y_in, f_in, x_out, y_out):
f_out = np.zeros((y_out.size, x_out.size))
for i in prange(f_out.shape[1]):
idx = np.searchsorted(x_in, x_out[i])
x1 = x_in[idx-1]
x2 = x_in[idx]
x = x_out[i]
for j in prange(f_out.shape[0]):
idy = np.searchsorted(y_in, y_out[j])
y1 = y_in[idy-1]
y2 = y_in[idy]
y = y_out[j]
f11 = f_in[idy-1, idx-1]
f21 = f_in[idy-1, idx]
f12 = f_in[idy, idx-1]
f22 = f_in[idy, idx]
f_out[j, i] = ((f11 * (x2 - x) * (y2 - y) +
f21 * (x - x1) * (y2 - y) +
f12 * (x2 - x) * (y - y1) +
f22 * (x - x1) * (y - y1)) /
((x2 - x1) * (y2 - y1)))
return f_out
我们制作了一个相当大的插值数组来评估每种方法的性能。
示例函数是,
x = np.linspace(0, 4, 13)
y = np.array([0, 2, 3, 3.5, 3.75, 3.875, 3.9375, 4])
X, Y = np.meshgrid(x, y)
Z = np.sin(np.pi*X/2) * np.exp(Y/2)
x2 = np.linspace(0, 4, 1000)
y2 = np.linspace(0, 4, 1000)
Z2 = bilinear_interpolation(x, y, Z, x2, y2)
fun = interp2d(x, y, Z, kind='linear')
Z3 = fun(x2, y2)
fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(10, 6))
ax[0].pcolormesh(X, Y, Z, shading='auto')
ax[0].set_title("Original function")
X2, Y2 = np.meshgrid(x2, y2)
ax[1].pcolormesh(X2, Y2, Z2, shading='auto')
ax[1].set_title("bilinear interpolation")
ax[2].pcolormesh(X2, Y2, Z3, shading='auto')
ax[2].set_title("Scipy bilinear function")
plt.show()
性能测试
没有 numba 库的 Python
bilinear_interpolation函数,在这种情况下,与numba版本相同,只是我们在for循环中将prange更改为python普通range,并删除函数装饰器jit
%timeit bilinear_interpolation(x, y, Z, x2, y2)
每个循环提供 7.15 秒 ± 107 毫秒(7 次运行的平均值 ± 标准偏差,每次 1 个循环)
Python 与 numba numba
%timeit bilinear_interpolation(x, y, Z, x2, y2)
每个循环提供 2.65 毫秒 ± 70.5 微秒(7 次运行的平均值 ± 标准偏差,每次 100 次循环)
Scipy 实现
%%timeit
f = interp2d(x, y, Z, kind='linear')
Z2 = f(x2, y2)
每个循环提供 6.63 ms ± 145 µs(平均值 ± 标准偏差,7 次运行,每次 100 个循环)
在“Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz”上执行性能测试