插值是离散函数逼近的重要方法,利用它可通过函数在有限个点处的取值状况,估算出函数在其他点处的近似值。与拟合不同的是,要求曲线通过所有的已知数据。SciPy的interpolate模块提供了许多对数据进行插值运算的函数,范围涵盖简单的一维插值到复杂多维插值求解。当样本数据变化归因于一个独立的变量时,就使用一维插值;反之样本数据归因于多个独立变量时,使用多维插值。
计算插值有两种基本的方法,1、对一个完整的数据集去拟合一个函数;2、对数据集的不同部分拟合出不同的函数,而函数之间的曲线平滑对接。第二种方法又叫做仿样内插法,当数据拟合函数形式非常复杂时,这是一种非常强大的工具。我们首先介绍怎样对简单函数进行一维插值运算,然后进一步深入比较复杂的多维插值运算。
1. 一维插值interp1d()
一维数据的插值运算可以通过函数interp1d()完成。其调用形式如下,它实际上不是函数而是一个类:
类scipy.interpolate.interp1d(x,y,kind ='linear',axis = -1,copy = True,bounds_error = None,fill_value = nan,假定_sorted = False)
内插一维函数。
x和y是用于近似某些函数f:的值的数组 。此类返回一个函数,该函数的调用方法使用插值法查找新点的值。y = f(x)
请注意,
参量:
x :(N,)array_like
一维实数数组。
y :(...,N,...)array_like
ND实数值数组。沿插值轴的y长度必须等于x的长度。
kind: str or int, optional
将内插类型指定为字符串(“线性”,“最近”,“零”,“线性”,“二次”,“三次”,“上一个”,“下一个”,其中“零”,“线性”,“ “ quadratic”和“ cubic”是指零阶,一阶,二阶或三阶的样条插值;“ previous”和“ next”仅返回该点的上一个或下一个值)或作为指定样条顺序的整数内插器使用。默认值为“线性”。
axis : int, optional
指定要沿其进行插值的y轴。插值默认为y的最后一个轴。
copy : bool, optional
如果为True,则该类将制作x和y的内部副本。如果为False,则使用对x和y的引用。默认为复制。
bounds_error : bool, optional
如果为True,则任何时候尝试对x范围之外的值进行插值都会引发ValueError(需要进行插值)。如果为False,则分配超出范围的值fill_value="extrapolate"。
fill_value : array-like or (array-like, array_like) or “extrapolate”, optional如果是ndarray(或float),则此值将用于填充数据范围之外的请求点。如果未提供,则默认值为NaN。类阵列必须正确广播到非插值轴的尺寸。
如果是二元组,则第一个元素用作的填充值,第二个元素 用作的填充值。不是2元素元组的任何元素(例如list或ndarray,不考虑形状)都被视为一个类似数组的自变量,意味着将两个边界都用作 。x_new < x[0]x_new > x[-1]below, above = fill_value, fill_value
如果“外推”,则数据范围外的点将被外推。
assume_sorted : bool, optional
如果为False,则x的值可以按任何顺序排列,并且将首先对其进行排序。如果为True,则x必须是单调递增值的数组。
下面的程序演示了通过不同的 kind参数,对一个正弦函数进行插值运算。示例代码:
import numpy as np
from scipy import interpolate
import pylab as pl
x=np.linspace(0,10,11)
y=np.sin(x)
xnew=np.linspace(0,10,101)
pl.plot(x,y,'ro')
list1=['linear','nearest']
list2=[0,1,2,3]
for kind in list1:
print(kind)
f=interpolate.interp1d(x,y,kind=kind)
#f是一个函数,用这个函数就可以找插值点的函数值了:
ynew=f(xnew)
pl.plot(xnew,ynew,label=kind)
pl.legend(loc='lower right')
pl.show()
interp1d比Matlab的interp有些优势,因为返回的是函数,不需要在事先设定需要求解的点,而是在需要使用时调用函数。
这个是linear和nearest的效果:
这个是zero, slinear, quadratic, cubic
也就是0, 1, 2, 3 次样条插值,所以这里的参数可以用str,也可以用数字
nterp1d不能外推运算(外插值)
UnivariateSpline可以外插值
调用方式如下:
UnivariateSpline(x,y,w=None,bbox=[None,None],k=3,s=None)x,y是X-Y坐标数组
w是每个数据点的权重值
k为样条曲线的阶数
s为平滑参数。s=0,样条曲线强制通过所有数据点
s>0,满足
from scipy import interpolate
import numpy as np
x1=np.linspace(0,10,20)
y1=np.sin(x1)
sx1=np.linspace(0,12,100)
func1=interpolate.UnivariateSpline(x1,y1,s=0)#强制通过所有点
sy1=func1(sx1)
import matplotlib.pyplot as plt
plt.plot(x1,y1,'o')
plt.plot(sx1,sy1)
plt.show()
也就插值到(0,12),范围再大就不行了,毕竟插值的专长不在于预测
import numpy as np
from scipy import interpolate
x2=np.linspace(0,20,200)
y2=np.sin(x2)+np.random.normal(loc=0,scale=1,size=len(x2))*0.2
sx2=np.linspace(0,22,2000)
func2=interpolate.UnivariateSpline(x2,y2,s=8)
sy2=func2(sx2)
import matplotlib.pyplot as plt
plt.plot(x2,y2,'.')
plt.plot(sx2,sy2)
plt.show()
interp2d(x,y,z,kind='linear')
这里有几个注意事项:interp2d()中,输入的x,y,z先用ravel()被转成了一维数组
func()的输入必须是一维的,输出是二维的(有点奇怪,感觉完成度不高)
插值的源数据必须是等距网格。不然的haul,运行不保存但结果不对。
step1:生成数据
import numpy as np
def func(x,y):
return (x+y)*np.exp(-5*(x**2+y**2))
x,y=np.mgrid[-1:1:8j,-1:1:8j]
z=func(x,y)
step2:插值
from scipy import interpolate
func=interpolate.interp2d(x,y,z,kind='cubic')
xnew=np.linspace(-1,1,100)
ynew=np.linspace(-1,1,100)
znew=func(xnew,ynew)#xnew, ynew是一维的,输出znew是二维的
xnew,ynew=np.mgrid[-1:1:100j,-1:1:100j]#统一变成二维,便于下一步画图
step3:画图
import mpl_toolkits.mplot3d
import matplotlib.pyplot as plt
ax=plt.subplot(111,projection='3d')
ax.plot_surface(xnew,ynew,znew)
ax.scatter(x,y,z,c='r',marker='^')
plt.show()
Rbf的优点是,排列可以无序,可以不是等距的网格
step1:随机生成点,并计算函数值
import numpy as np
def func(x,y):
return (x+y)*np.exp(-5*(x**2+y**2))
x=np.random.uniform(low=-1,high=1,size=100)
y=np.random.uniform(low=-1,high=1,size=100)
z=func(x,y)
step2:插值
from scipy import interpolate
func=interpolate.Rbf(x,y,z,function='multiquadric')
xnew,ynew=np.mgrid[-1:1:100j,-1:1:100j]
znew=func(xnew,ynew)#输入输出都是二维
step3:画图
import mpl_toolkits.mplot3d
import matplotlib.pyplot as plt
ax=plt.subplot(111,projection='3d')
ax.plot_surface(xnew,ynew,znew)
ax.scatter(x,y,z,c='r',marker='^')
plt.show()