使用scipy interp2d
函数时,我输入错误无效。事实证明问题来自bisplrep
函数,如下所示:
import numpy as np
from scipy import interpolate
# Case 1
x = np.linspace(0,1)
y = np.zeros_like(x)
z = np.ones_like(x)
tck = interpolate.bisplrep(x,y,z) # or interp2d
返回:ValueError: Invalid inputs
事实证明,我给出的interp2d
测试数据只包含第二轴的一个不同值,如上面的测试样本所示。 bisplrep
内的interp2d
函数将其视为无效输出:
这可被视为可接受的行为:interp2d
& bisplrep
期待一个2D网格,而我只是在一行上给它们值。
在旁注中,我发现错误信息很不清楚。可以在interp2d
中包含一个测试以处理此类案例:
if len(np.unique(x))==1 or len(np.unique(y))==1:
ValueError ("Can't build 2D splines if x or y values are all the same")
可能足以检测到这种无效输入,并引发更明确的错误消息,甚至直接调用更合适的interp1d
函数(这在这里完美运行)
我以为我已经正确地理解了这个问题。但是,请考虑以下代码示例:
# Case 2
x = np.linspace(0,1)
y = x
z = np.ones_like(x)
tck = interpolate.bisplrep(x,y,z)
在这种情况下,y
与x
成比例,我也在向bisplrep
提供一行数据。但是,令人惊讶的是,bisplrep
能够在这种情况下计算2D样条插值。我画了它:
# Plot
def plot_0to1(tck):
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
X = np.linspace(0,1,10)
Y = np.linspace(0,1,10)
Z = interpolate.bisplev(X,Y,tck)
X,Y = np.meshgrid(X,Y)
fig = plt.figure()
ax = Axes3D(fig)
ax.plot_surface(X, Y, Z,rstride=1, cstride=1, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
plt.show()
plot_0to1(tck)
结果如下:
其中bisplrep
似乎用0填补了空白,当我扩展下图时更好地显示:
关于是否需要添加0,我真正的问题是:为什么bisplrep
在案例2中工作但在案例1中没有?
或者换句话说:当2D插值仅沿一个方向输入(情况1和2失败)时,我们是否希望它返回错误? (案例1和2应该返回一些东西,即使是不可预测的)。
答案 0 :(得分:8)
如果您的输入数据沿坐标轴而不是某些方向定向,我原本会向您展示它对二维插值有多大差异,但事实证明结果会比我更加混乱曾经预料过。我尝试在插值矩形网格上使用随机数据集,并将其与相同x
和y
坐标旋转45度进行插值的情况进行比较。结果很糟糕。
然后我尝试与更平滑的数据集进行比较:结果scipy.interpolate.interp2d
有很多问题。所以我的底线将是“使用scipy.interpolate.griddata
”。
出于指导性目的,这是我的(相当混乱的)代码:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.cm as cm
n = 10 # rough number of points
dom = np.linspace(-2,2,n+1) # 1d input grid
x1,y1 = np.meshgrid(dom,dom) # 2d input grid
z = np.random.rand(*x1.shape) # ill-conditioned sample
#z = np.cos(x1)*np.sin(y1) # smooth sample
# first interpolator with interp2d:
fun1 = interp.interp2d(x1,y1,z,kind='linear')
# construct twice finer plotting and interpolating mesh
plotdom = np.linspace(-1,1,2*n+1) # for interpolation and plotting
plotx1,ploty1 = np.meshgrid(plotdom,plotdom)
plotz1 = fun1(plotdom,plotdom) # interpolated points
# construct 45-degree rotated input and interpolating meshes
rotmat = np.array([[1,-1],[1,1]])/np.sqrt(2) # 45-degree rotation
x2,y2 = rotmat.dot(np.vstack([x1.ravel(),y1.ravel()])) # rotate input mesh
plotx2,ploty2 = rotmat.dot(np.vstack([plotx1.ravel(),ploty1.ravel()])) # rotate plotting/interp mesh
# interpolate on rotated mesh with interp2d
# (reverse rotate by using plotx1, ploty1 later!)
fun2 = interp.interp2d(x2,y2,z.ravel(),kind='linear')
# I had to generate the rotated points element-by-element
# since fun2() accepts only rectangular meshes as input
plotz2 = np.array([fun2(xx,yy) for (xx,yy) in zip(plotx2.ravel(),ploty2.ravel())])
# try interpolating with griddata
plotz3 = interp.griddata(np.array([x1.ravel(),y1.ravel()]).T,z.ravel(),np.array([plotx1.ravel(),ploty1.ravel()]).T,method='linear')
plotz4 = interp.griddata(np.array([x2,y2]).T,z.ravel(),np.array([plotx2,ploty2]).T,method='linear')
# function to plot a surface
def myplot(X,Y,Z):
fig = plt.figure()
ax = Axes3D(fig)
ax.plot_surface(X, Y, Z,rstride=1, cstride=1,
linewidth=0, antialiased=False,cmap=cm.coolwarm)
plt.show()
# plot interp2d versions
myplot(plotx1,ploty1,plotz1) # Cartesian meshes
myplot(plotx1,ploty1,plotz2.reshape(2*n+1,-1)) # rotated meshes
# plot griddata versions
myplot(plotx1,ploty1,plotz3.reshape(2*n+1,-1)) # Cartesian meshes
myplot(plotx1,ploty1,plotz4.reshape(2*n+1,-1)) # rotated meshes
所以这是一个结果库。使用随机输入z
数据和interp2d
,笛卡儿(左)与旋转插值(右):
注意右侧可怕的比例,注意输入点介于0
和1
之间。即使是母亲也不会认出数据集。请注意,在评估旋转数据集期间会有运行时警告,因此我们会收到警告,它们都是废话。
现在让我们对griddata
:
我们应该注意到这些数字彼此更接近,并且它们似乎使方式比interp2d
的输出更有意义。例如,请注意第一个数字的比例过冲。
这些工件总是出现在输入数据点之间。由于它仍然是插值,输入点必须通过插值函数再现,但线性插值函数在数据点之间过冲是非常奇怪的。很明显griddata
不会遇到这个问题。
考虑一个更加清晰的案例:另一组z
值,它们是平滑且确定的。具有interp2d
的表面:
HELP!叫插值警察!笛卡尔输入案例中已经出现了令人费解的(好吧,至少是我)虚假的特征,并且旋转的输入案例构成了s͔̖̰͕̞͖͇͔̖̰͕̞͖͇͇̹̞̳ͣ̈̒ͦͣ̈̒ͦͭ̊̓̈m̥̠͈̣̆̐ͦ̚m̻͑͒̔̓ͦ̇oͣ̐ͣṉ̟͖͙̆͋i͉̓̓ͭ̒͛n̹̙̥̩̥̯̭ͤͤͤ̄g͈͇̼͖͖̭̙͈͇̼͖͖̭̙z̻̉ͬͪ̑ͭͨ͊ǟ̼̣̬̗̖ͥl̫̣͔͓̟͛͊̏ͨ͗g̻͇͈͚̟̻͛ͫ͛̅͋͒o͈͓̥̙̫͚̾的威胁。
让我们对griddata
:
由于飞天小女警 scipy.interpolate.griddata
,这一天得救了。作业:使用cubic
插值检查相同。
顺便说一句,对原始问题的回答很简短,就在help(interp.interp2d)
:
| Notes
| -----
| The minimum number of data points required along the interpolation
| axis is ``(k+1)**2``, with k=1 for linear, k=3 for cubic and k=5 for
| quintic interpolation.
对于线性插值,您需要沿插值轴至少4个点,即必须至少有4个唯一x
和y
值才能获得有意义的结果。检查这些:
nvals = 3 # -> RuntimeWarning
x = np.linspace(0,1,10)
y = np.random.randint(low=0,high=nvals,size=x.shape)
z = x
interp.interp2d(x,y,z)
nvals = 4 # -> no problem here
x = np.linspace(0,1,10)
y = np.random.randint(low=0,high=nvals,size=x.shape)
z = x
interp.interp2d(x,y,z)
当然这一切都与你提出这样的问题:如果你的几何1d数据集沿着一个笛卡尔坐标轴,或者如果它是一般的方式使得坐标值呈现各种不同,那么它会产生很大的不同值。从几何1d数据集中尝试二维插值可能毫无意义(或至少非常不明确),但如果您的数据沿着x,y
平面的大致方向,则至少算法不应该中断。 / p>