【问题标题】:linear interpolation -- make grid线性插值——制作网格
【发布时间】:2017-02-04 09:45:44
【问题描述】:

我想在不同模型之间进行插值。为方便起见,我的数据如下所示:

我有 10 种不同的模拟(我称之为z)。对于每个z,我都有一个array x 和一个array y(对于给定的zlen(x)=len(y))。 例如:

对于z=1x.shape=(1200,)y.shape=(1200,)

对于z=2x.shape=(1250,)y.shape=(1250,)

对于z=3x.shape=(1236,)y.shape=(1236,)

等等……

我想进行插值,以便对于给定的zx,我得到y。例如,对于z=2.5x=10**9,代码输出y。我假设:

y = a*x + b*z + c 我当然不知道abc

我的问题是如何将数据存储在网格中?我很困惑,因为对于不同的zxy 的大小不同。怎么可能建立一个网格?

更新

我能够部分解决我的问题。我首先做的是使用interp1dxy 之间进行插值。它工作得很好。然后,我创建了xy 值的新网格。简单来说方法是:

f = interp1d(x, y, kind='linear')
new_x = np.linspace(10**7, 4*10**9, 10000)
new_y = f(new_x)

然后我对xyz 进行插值:

ff = LinearNDInterpolator( (x, z), y)

为了测试该方法是否有效,这里有一个带有z=3 的图。

x=10**8 之前,情节看起来不错。事实上,这条线偏离了原始模型。这是我进一步放大时的情节:

x > 10**8 时插值明显不好。我该如何解决?

【问题讨论】:

  • x 之间有标准间距吗?网格是必要的,还是只是简单的查找?如果只是简单的查找,您可以将所有内容放在dictdict 中,如my_y = ys[my_z][my_x]
  • This 可能类似。
  • @rbierman,网格是必要的,因为我想在不同模型之间进行插值。 x 之间没有标准间距,它们是随机的。
  • @aloha 好的,这听起来是个难题。你能解释一下为什么你在上面设置z=2.5,我认为z是模拟数字(一个int)?模型之间的插值是否意味着将模型平均在一起?如果它们不共享 x,则在比较模型与模型之前,您必须在每个模型中进行某种插值。
  • @rbierman,我以z=2.5为例,我可以说z=2.3546372。这是一个完全随机的数字。这些模型没有共享相同的x。我想先尝试在xy 之间进行插值,然后再包括z。 Andra 的链接与我正在寻找的类似。

标签: python interpolation linear-interpolation


【解决方案1】:

似乎在您的问题中,曲线 y(x) 表现良好,因此您可以先对给定的 z 值插值 y(x),然后再在获得的 y 值之间插值。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider

import random

#####
# Generate some data
#####
generate = lambda x, z: 1./(x+1.)+(z*x/75.+z/25.)

def f(z):
    #create an array of values between zero and 100 of random length
    x = np.linspace(0,10., num=random.randint(42,145))
    #generate corresponding y values
    y = generate(x, z)
    return np.array([x,y])

Z = [1, 2, 3, 3.6476, 4, 5.1]
A = [f(z) for z in Z]
#now A contains the dataset of [x,y] pairs for each z value

#####
# Interpolation
#####
def do_interpolation(x,z):
    #assume Z being sorted in ascending order
    #look for indizes of z values closest to given z
    ig = np.searchsorted(Z, z)
    il = ig-1
    #interpolate y(x) for those z values
    yg = np.interp(x, A[ig][0,:], A[ig][1,:])
    yl = np.interp(x, A[il][0,:], A[il][1,:])
    #linearly interpolate between yg and yl  
    return yl + (yg-yl)*float(z-Z[il])/(Z[ig] - Z[il])  

# do_interpolation(x,z) will now provide the interpolated data
print do_interpolation( np.linspace(0, 10), 2.5) 

#####
# Plotting, use Slider to change the value of z. 
#####
fig=plt.figure()
fig.subplots_adjust(bottom=0.2)
ax=fig.add_subplot(111)
for i in range(len(Z)):
    ax.plot(A[i][0,:] , A[i][1,:], label="{z}".format(z=Z[i]) )

l, = ax.plot(np.linspace(0, 10) , do_interpolation( np.linspace(0, 10), 2.5), label="{z}".format(z="interpol"), linewidth=2., color="k" )

axn1 = plt.axes([0.25, 0.1, 0.65, 0.03], axisbg='#e4e4e4')
sn1 = Slider(axn1, 'z', Z[0], Z[-1], valinit=2.5)
def update(val):
    l.set_data(np.linspace(0, 10), do_interpolation( np.linspace(0, 10), val))
    plt.draw()
sn1.on_changed(update)

ax.legend()
plt.show()

【讨论】:

    【解决方案2】:

    你所做的对我来说似乎有点奇怪,至少你似乎使用一组 y 值来进行插值。我的建议不是一个接一个地执行两个插值,而是将您的 y(z,x) 函数视为纯二维插值问题的结果。

    正如我在评论中指出的那样,我建议使用scipy.interpolate.LinearNDInterpolator,这是griddata 在引擎盖下用于双线性插值的同一对象。正如我们在 cmets 中讨论的那样,您需要一个可以在之后多次查询的插值器,因此我们必须使用较低级别的插值器对象,因为它是可调用的。

    这是我的意思的完整示例,包含虚拟数据和绘图:

    import numpy as np
    import scipy.interpolate as interp
    import matplotlib.pyplot as plt
    
    # create dummy data
    zlist = range(4)  # z values
    # one pair of arrays for each z value in a list:
    xlist = [np.linspace(-1,1,41),
             np.linspace(-1,1,61),
             np.linspace(-1,1,55),
             np.linspace(-1,1,51)]
    funlist = [lambda x:0.1*np.ones_like(x),
               lambda x:0.2*np.cos(np.pi*x)+0.4,
               lambda x:np.exp(-2*x**2)+0.5,
               lambda x:-0.7*np.abs(x)+1.7]
    ylist = [f(x) for f,x in zip(funlist,xlist)]
    
    # create contiguous 1d arrays for interpolation
    all_x = np.concatenate(xlist)
    all_y = np.concatenate(ylist)
    all_z = np.concatenate([np.ones_like(x)*z for x,z in zip(xlist,zlist)])
    
    # create a single linear interpolator object
    yfun = interp.LinearNDInterpolator((all_z,all_x),all_y)
    
    # generate three interpolated sets: one with z=2 to reproduce existing data,
    # two with z=1.5 and z=2.5 respectively to see what happens
    xplot = np.linspace(-1,1,30)
    z = 2
    y_repro = yfun(z,xplot)
    z = 1.5
    y_interp1 = yfun(z,xplot)
    z = 2.5
    y_interp2 = yfun(z,xplot)
    
    # plot the raw data (markers) and the two interpolators (lines)
    fig,ax = plt.subplots()
    for x,y,z,mark in zip(xlist,ylist,zlist,['s','o','v','<','^','*']):
        ax.plot(x,y,'--',marker=mark,label='z={}'.format(z))
    ax.plot(xplot,y_repro,'-',label='z=2 interp')
    ax.plot(xplot,y_interp1,'-',label='z=1.5 interp')
    ax.plot(xplot,y_interp2,'-',label='z=2.5 interp')
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    # reduce plot size and put legend outside for prettiness, see also http://stackoverflow.com/a/4701285/5067311
    box = ax.get_position()
    ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])
    ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
    
    plt.show()
    

    您没有指定如何存储一系列 (x,y) 数组对,我使用了一个 numpy ndarrays 列表。如您所见,我将一维数组列表展平为一组一维数组:all_xall_yall_z。这些可以用作分散的y(z,x) 数据,您可以从中构造插值器对象。正如您在结果中看到的,对于z=2,它再现了输入点,对于非整数z,它在相关的y(x) 曲线之间进行插值。

    此方法应该适用于您的数据集。但是,请注意:x 轴上有大量的对数刻度。仅此一项就可能导致数值不稳定。我建议您也尝试使用log(x) 执行插值,它可能会表现得更好(这只是一个模糊的猜测)。

    【讨论】:

      猜你喜欢
      • 2012-06-07
      • 2012-12-16
      • 2015-06-27
      • 2017-05-18
      • 2017-02-22
      • 2019-12-08
      • 2013-07-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多