Python 如何使用scipy获得非平滑二维样条插值

Python 如何使用scipy获得非平滑二维样条插值,python,scipy,interpolation,curve-fitting,spline,Python,Scipy,Interpolation,Curve Fitting,Spline,我想要一个二维三次样条曲线来拟合一些不必要的间隔数据,也就是说,一个函数精确地拟合给定点上的数据,但也可以返回介于两者之间的值 我所能找到的(对于非比例间隔数据)是scipy.interpolate.SmoothBivariateSpline。我不知道如何关闭“平滑”(无论我在s参数中输入了什么值) 然而,我发现我可以通过scipy.interpolate.griddata得到我想要的东西,尽管每次都要重新计算它(也就是说,不只是生成一个函数)。这两者之间有什么本质上的区别吗?即,griddat

我想要一个二维三次样条曲线来拟合一些不必要的间隔数据,也就是说,一个函数精确地拟合给定点上的数据,但也可以返回介于两者之间的值

我所能找到的(对于非比例间隔数据)是
scipy.interpolate.SmoothBivariateSpline
。我不知道如何关闭“平滑”(无论我在
s
参数中输入了什么值)

然而,我发现我可以通过
scipy.interpolate.griddata
得到我想要的东西,尽管每次都要重新计算它(也就是说,不只是生成一个函数)。这两者之间有什么本质上的区别吗?即,
griddata
是否做了与“样条线”不同的事情?是否有必要关闭
SmoothBivariateSpline
或不平滑的等效函数中的平滑

下面是我用来测试样条曲线与多项式拟合的脚本

import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import scipy.optimize
import scipy.interpolate
import matplotlib.pyplot as plt
import numpy.polynomial.polynomial as poly


# Grid and test function
N = 9;
x,y = np.linspace(-1,1, N), np.linspace(-1,1, N)
X,Y = np.meshgrid(x,y)
F = lambda X,Y : X+Y-1*X*Y-(X*Y)**2 -2*X*Y**2 + X**2*Y + 3*np.exp(-((X+1)**2+(Y+1)**2)*5)
Z = F(X,Y)
noise = 0.4
Z *= 1+(np.random.random(Z.shape)*2-1)*noise # noise

# Finer Grid and test function
N2 = 19;
x2,y2 = np.linspace(-1,1, N2), np.linspace(-1,1, N2)
X2,Y2 = np.meshgrid(x2,y2)
Z2 = F(X2,Y2)

# Make data into lists
Xl = X.reshape(X.size)
Yl = Y.reshape(Y.size)
Zl = Z.reshape(Z.size)

# Polynomial fit
# polyval(x,y,p) = p[0,0]+p[0,1]y+p[1,0]x+p[1,1]xy+p[1,2]xy^2 ..., etc
# I use a flat (1D) array for p, so it needs to be reshaped into a 2D array before
# passing to polyval
order = 3
p0 = np.zeros(order**2) # guess parameters (all 0 for now)
f_poly = lambda x,y,p : poly.polyval2d(x,y,p.reshape((order,order))) # Wrapper for our polynomial
errf = lambda p : np.mean((f_poly(Xl,Yl,p.reshape((order,order)))-Zl)**2) # error function to find least square error
sol = scipy.optimize.minimize(errf, p0)
psol = sol['x']

# Spline interpolation
# Bivariate (2D), Smoothed (doesn't fit points *exactly*)  cubic (3rd order - i.e. kx=ky=3) spline
spl = scipy.interpolate.SmoothBivariateSpline(Xl, Yl, Zl, kx=3,ky=3)
f_spline = spl.ev

# regular Interpolate
f_interp = lambda x,y : scipy.interpolate.griddata((Xl, Yl), Zl, (x,y), method='cubic')

# Plot
fig = plt.figure(1, figsize=(7,8))
plt.clf()

# poly fit
ax = fig.add_subplot(311, projection='3d')
ax.scatter3D(X2,Y2,Z2,s=3, color='red', label='actual data')
fit = f_poly(X2,Y2, psol)
l = 'order {} poly fit'.format(order)
ax.plot_wireframe(X2,Y2, fit, color='black', label=l)
ax.scatter3D(X,Y,Z, color='blue', label='noisy data')
plt.legend()
print("Average {} error: {}".format(l, np.sqrt(np.mean((fit-Z2)**2))))

# spline fit
ax = fig.add_subplot(312, projection='3d')
ax.scatter3D(X2,Y2,Z2,s=3, color='red', label='actual data')
l = 'smoothed spline'
fit = f_spline(X2,Y2)
ax.plot_wireframe(X2,Y2, fit, color='black', label=l)
ax.scatter3D(X,Y,Z, color='blue', label='noisy data')
plt.legend()
print("Average {} error: {}".format(l, np.sqrt(np.mean((fit-Z2)**2))))

# interp fit
ax = fig.add_subplot(313, projection='3d')
ax.scatter3D(X2,Y2,Z2,s=3, color='red', label='actual data')
l='3rd order interp '
fit=f_interp(X2,Y2)
ax.plot_wireframe(X2,Y2, fit, color='black', label=l)
ax.scatter3D(X,Y,Z, color='blue', label='noisy data')
plt.legend()
print("Average {} error: {}".format(l, np.sqrt(np.mean((fit-Z2)**2))))

plt.show(False)
plt.pause(1)

raw_input('press key to continue') # Change to input() if using python3

对于非结构化网格,
griddata
是正确的插值工具。但是,三角剖分(Delaunay)每次都会执行插值。一种解决方法是使用C1平滑插值或线性插值。这些函数实际上由
griddata
使用。不同之处在于,可以将其用作输入a,并返回插值函数

以下是基于您的代码的示例:

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

import numpy as np
from scipy.interpolate import CloughTocher2DInterpolator
from scipy.spatial import Delaunay

# Example unstructured mesh:
nodes = np.array([[-1.        , -1.        ],
       [ 1.        , -1.        ],
       [ 1.        ,  1.        ],
       [-1.        ,  1.        ],
       [ 0.        ,  0.        ],
       [-1.        ,  0.        ],
       [ 0.        , -1.        ],
       [-0.5       ,  0.        ],
       [ 0.        ,  1.        ],
       [-0.75      ,  0.4       ],
       [-0.5       ,  1.        ],
       [-1.        , -0.6       ],
       [-0.25      , -0.5       ],
       [-0.5       , -1.        ],
       [-0.20833333,  0.5       ],
       [ 1.        ,  0.        ],
       [ 0.5       ,  1.        ],
       [ 0.36174242,  0.44412879],
       [ 0.5       , -0.03786566],
       [ 0.2927264 , -0.5411368 ],
       [ 0.5       , -1.        ],
       [ 1.        ,  0.5       ],
       [ 1.        , -0.5       ]])

# Theoretical function:
def F(x, y):
    return x + y -  x*y - (x*y)**2 - 2*x*y**2 + x**2*y + 3*np.exp( -((x+1)**2 + (y+1)**2)*5 )

z = F(nodes[:, 0], nodes[:, 1])

# Finer regular grid:
N2 = 19
x2, y2 = np.linspace(-1, 1, N2), np.linspace(-1, 1, N2)
X2, Y2 = np.meshgrid(x2, y2)

# Interpolation:
tri = Delaunay(nodes)
CT_interpolator = CloughTocher2DInterpolator(tri, z)
z_interpolated = CT_interpolator(X2, Y2)

# Plot
fig = plt.figure(1, figsize=(8,14))

ax = fig.add_subplot(311, projection='3d')
ax.scatter3D(nodes[:, 0], nodes[:, 1], z, s=15, color='red', label='points')

ax.plot_wireframe(X2, Y2, z_interpolated, color='black', label='interpolated')
plt.legend();
得到的图形为:


样条线方法和Clough-Tocher插值都是基于在网格元素上构造分段多项式函数。不同之处在于,对于样条线,网格是规则的,并且由算法给出(请参见)。并且对系数进行拟合,以便函数尽可能接近点并平滑(拟合)。对于Clough-Tocher插值,网格元素是作为输入给定的元素。因此,结果函数保证通过点。

相关问题:对于您的应用,我认为高阶多边形将提供更令人满意的结果。二次样条线将始终平滑您的数据,因为它是二次样条线最好的ie是一个2阶多边形。你不是用kx,ky参数来设置顺序吗?另外-一个高阶多边形也会平滑数据(除非数据实际上是一个多边形)。是的,你说得很对。我收回我的评论。不是scipy.interpole.interp2d做同样的事情吗?根据文档()它可以接受不在常规网格上的输入,并且没有平滑的说法。