我有两个列表来描述函数 y(x):
x = [0,1,2,3,4,5]
y = [12,14,22,39,58,77]
我想执行三次样条插值,以便在 x 的域中给定一些值 u,例如
u = 1.25
我能找到 y(u)。
原文由 user112829 发布,翻译遵循 CC BY-SA 4.0 许可协议
我有两个列表来描述函数 y(x):
x = [0,1,2,3,4,5]
y = [12,14,22,39,58,77]
我想执行三次样条插值,以便在 x 的域中给定一些值 u,例如
u = 1.25
我能找到 y(u)。
原文由 user112829 发布,翻译遵循 CC BY-SA 4.0 许可协议
如果未安装 scipy:
import numpy as np
from math import sqrt
def cubic_interp1d(x0, x, y):
"""
Interpolate a 1-D function using cubic splines.
x0 : a float or an 1d-array
x : (N,) array_like
A 1-D array of real/complex values.
y : (N,) array_like
A 1-D array of real values. The length of y along the
interpolation axis must be equal to the length of x.
Implement a trick to generate at first step the cholesky matrice L of
the tridiagonal matrice A (thus L is a bidiagonal matrice that
can be solved in two distinct loops).
additional ref: www.math.uh.edu/~jingqiu/math4364/spline.pdf
"""
x = np.asfarray(x)
y = np.asfarray(y)
# remove non finite values
# indexes = np.isfinite(x)
# x = x[indexes]
# y = y[indexes]
# check if sorted
if np.any(np.diff(x) < 0):
indexes = np.argsort(x)
x = x[indexes]
y = y[indexes]
size = len(x)
xdiff = np.diff(x)
ydiff = np.diff(y)
# allocate buffer matrices
Li = np.empty(size)
Li_1 = np.empty(size-1)
z = np.empty(size)
# fill diagonals Li and Li-1 and solve [L][y] = [B]
Li[0] = sqrt(2*xdiff[0])
Li_1[0] = 0.0
B0 = 0.0 # natural boundary
z[0] = B0 / Li[0]
for i in range(1, size-1, 1):
Li_1[i] = xdiff[i-1] / Li[i-1]
Li[i] = sqrt(2*(xdiff[i-1]+xdiff[i]) - Li_1[i-1] * Li_1[i-1])
Bi = 6*(ydiff[i]/xdiff[i] - ydiff[i-1]/xdiff[i-1])
z[i] = (Bi - Li_1[i-1]*z[i-1])/Li[i]
i = size - 1
Li_1[i-1] = xdiff[-1] / Li[i-1]
Li[i] = sqrt(2*xdiff[-1] - Li_1[i-1] * Li_1[i-1])
Bi = 0.0 # natural boundary
z[i] = (Bi - Li_1[i-1]*z[i-1])/Li[i]
# solve [L.T][x] = [y]
i = size-1
z[i] = z[i] / Li[i]
for i in range(size-2, -1, -1):
z[i] = (z[i] - Li_1[i-1]*z[i+1])/Li[i]
# find index
index = x.searchsorted(x0)
np.clip(index, 1, size-1, index)
xi1, xi0 = x[index], x[index-1]
yi1, yi0 = y[index], y[index-1]
zi1, zi0 = z[index], z[index-1]
hi1 = xi1 - xi0
# calculate cubic
f0 = zi0/(6*hi1)*(xi1-x0)**3 + \
zi1/(6*hi1)*(x0-xi0)**3 + \
(yi1/hi1 - zi1*hi1/6)*(x0-xi0) + \
(yi0/hi1 - zi0*hi1/6)*(xi1-x0)
return f0
if __name__ == '__main__':
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 11)
y = np.sin(x)
plt.scatter(x, y)
x_new = np.linspace(0, 10, 201)
plt.plot(x_new, cubic_interp1d(x_new, x, y))
plt.show()
原文由 raphael valentin 发布,翻译遵循 CC BY-SA 3.0 许可协议
2 回答5k 阅读✓ 已解决
2 回答1.1k 阅读✓ 已解决
4 回答941 阅读✓ 已解决
3 回答1.1k 阅读✓ 已解决
3 回答1.1k 阅读✓ 已解决
1 回答1.7k 阅读✓ 已解决
1 回答1.2k 阅读✓ 已解决
简短回答:
长答案:
scipy 将样条插值中涉及的步骤分成两个操作,很可能是为了提高计算效率。
使用 splrep() 计算描述样条曲线的系数。 splrep 返回包含系数的元组数组。
这些系数被传递到 splev() 以实际评估所需点的样条
x
(在本例中为 1.25)。x
也可以是数组。 Callingf([1.0, 1.25, 1.5])
returns the interpolated points at1
,1.25
, and1,5
, respectively.诚然,这种方法对于单次评估不方便,但由于最常见的用例是从少数几个函数评估点开始,然后重复使用样条曲线找到插值,因此在实践中通常非常有用。