Python 线性插值——生成网格

Python 线性插值——生成网格,python,interpolation,linear-interpolation,Python,Interpolation,Linear Interpolation,我想在不同的模型之间进行插值。为了方便起见,我的数据如下所示: 我有10种不同的模拟(我称之为z)。对于每个z我有一个数组x和一个数组y(其中对于给定的z,len(x)=len(y))。 例如: 对于z=1:x.shape=(1200,)和y.shape=(1200,) 对于z=2:x.shape=(1250,)和y.shape=(1250,) 对于z=3:x.shape=(1236,)和y.shape=(1236,) 等等 我想插值,这样对于给定的z和x,我得到y。例如,对于z=2.5和x=

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

我有10种不同的模拟(我称之为
z
)。对于每个
z
我有一个
数组x
和一个
数组y
(其中对于给定的
z
len(x)=len(y)
)。 例如:

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

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

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

等等

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

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

我的问题是如何在网格中存储数据?我感到困惑,因为对于不同的
z
而言,
x
y
的大小不同。如何构建网格

更新 我能部分解决我的问题。首先,我使用
interp1d
x
y
之间插值。它工作得非常好。然后,我创建了一个包含
x
y
值的新网格。简单地说,方法是:

f = interp1d(x, y, kind='linear')
new_x = np.linspace(10**7, 4*10**9, 10000)
new_y = f(new_x)
然后我插入
x
y
,和
z

ff = LinearNDInterpolator( (x, z), y)
为了测试该方法是否有效,这里有一个z=3的图

x=10**8
之前,绘图效果良好。事实上,这条线偏离了原始模型。当我进一步放大时,这里有一个图:


x>10**8
时,插值明显不好。我如何修复它?

在您的问题中,曲线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()

在您的问题中,曲线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()

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

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

下面是我的意思的完整示例,包括虚拟数据和绘图:

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()
将numpy导入为np
导入scipy.interpolate作为interp
将matplotlib.pyplot作为plt导入
#创建虚拟数据
zlist=范围(4)#z值
#列表中每个z值对应一对数组:
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.one_-like(x),
λx:0.2*np.cos(np.pi*x)+0.4,
λx:np.exp(-2*x**2)+0.5,
λx:-0.7*np.abs(x)+1.7]
ylist=[f(x)表示f,zip中的x(funlist,xlist)]
#创建用于插值的连续一维阵列
all_x=np.连接(xlist)
all_y=np.concatenate(ylist)
all_z=np.连接([np.像(x)*z代表x,z在zip中(xlist,zlist)])
#创建单个线性插值器对象
yfun=内部线性交叉线((全部z,全部x),全部y)
#生成三个插值集:一个z=2以再现现有数据,
#两个分别为z=1.5和z=2.5,看看会发生什么
xplot=np.linspace(-1,1,30)
z=2
y_repo=yfun(z,xplot)
z=1.5
y_interp1=yfun(z,xplot)
z=2.5
y_interp2=yfun(z,xplot)
#绘制原始数据(标记)和两个插值器(线)
图,ax=plt.子批次()

对于x,y,z,mark in zip(xlist,ylist,zlist,['s','o','v','p>你所做的对我来说似乎有点奇怪,至少你似乎使用了一组
y
值来进行插值。我建议不要一个接一个地执行两次插值,而是考虑到你的
y(z,x)
功能是纯二维插值问题的结果

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

下面是我的意思的完整示例,包括虚拟数据和绘图:

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()
将numpy导入为np
导入scipy.interpolate作为interp
将matplotlib.pyplot作为plt导入
#创建虚拟数据
zlist=范围(4)#z值
#列表中每个z值对应一对数组:
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.one_-like(x),
λx:0.2*np.cos(np.pi*x)+0.4,
λx:np.exp(-2*x**2)+0.5,
λx:-0.7*np.abs(x)+1.7]
ylist=[f(x)表示f,zip中的x(funlist,xlist)]
#创建用于插值的连续一维阵列
all_x=np.连接(xlist)
all_y=np.concatenate(ylist)
all_z=np.连接([np.像(x)*z代表x,z在zip中(xlist,zlist)])
#创建单个线性插值器对象
yfun=内部线性交叉线((全部z,全部x),全部y)
#生成三个插值集:一个z=2以再现现有的