python插值计算

一维插值

常规用法

【参考文章】
python实现各种插值法(数值分析)
python scipy样条插值函数大全(interpolate里interpld函数)
Python:插值interpolate模块
示例代码

# -*-coding:utf-8 -*-
import numpy as np
from scipy import interpolate
import pylab as pl

x=np.linspace(0,10,11)
#x=[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
y=np.sin(x)
xnew=np.linspace(0,10,101)
pl.plot(x,y,"ro")

for kind in ["nearest","zero","slinear","quadratic","cubic"]:#插值方式
 #"nearest","zero"为阶梯插值
 #slinear 线性插值
 #"quadratic","cubic" 为2阶、3阶B样条曲线插值
 f=interpolate.interp1d(x,y,kind=kind)
 # ‘slinear', ‘quadratic' and ‘cubic' refer to a spline interpolation of first, second or third order)
 ynew=f(xnew)
 pl.plot(xnew,ynew,label=str(kind))
pl.legend(loc="lower right")
pl.show()

处理外推

当插值超出范围的时候如果不加处理会导致报错,这时有如下几个方案。
【参考文章】
插值超出Python范围
如何使scipy.interpolate给出超出输入范围的外推结果?

在interpolate下设置bounds_error和fill_value

bounds_error:布尔值,可选
如果为True,则任何时候尝试对x范围之外的值进行插值都会引发ValueError(需要进行插值)。如果为False,则为边界值分配fill_value。fill_value默认情况下返回Nan,如果采用外推则设置fill_value=“extrapolate”。

import numpy as np
from scipy import interpolate

x = np.arange(0,10)
y = np.exp(-x/3.0)
f = interpolate.interp1d(x, y, bounds_error=False,fill_value="extrapolate")

print(f(9),np.exp(-9/3),f(9)-np.exp(-9/3))  
#0.049787068367863944 0.049787068367863944 0.0
print(f(11),np.exp(-11/3),f(11)-np.exp(-11/3)) 
#0.049787068367863944 0.025561533206507402 0.024225535161356542

由于外推部分是线性外推,所以对于非线性函数会有些许误差。
当然fill_value也可以是具体的值,比如0,或者边界值y[-1](但要注意设置边界值的话可能出现左侧溢出却返回右侧边界值的情况,此时应做相应处理,或者采用下面的interp函数。

采用interp

interp是将左侧和右侧的边界值直接作为超出范围的部分,而且使用格式与interpolate有些不同

import numpy as np
from scipy import interp

x = np.arange(0,10)
y = np.exp(-x/3.0)
interp([9,10],x, y)  #两个插值返回结果相同

自编外推插值函数

参考文章 如何使scipy.interpolate给出超出输入范围的外推结果?

单变量插值UnivariateSpline

参考文章 Python:插值interpolate模块
UnivariateSpline可以外插值
调用方式如下:

UnivariateSpline(x,y,w=None,bbox=[None,None],k=3,s=None)
  • x,y是X-Y坐标数组
  • w是每个数据点的权重值
  • k为样条曲线的阶数
  • s为平滑参数。
  • s=0,样条曲线强制通过所有数据点
  • s>0,满足 ∑ ( w ( y − spline ⁡ ( x ) ) ) 2 ≤ s \sum(w(y-\operatorname{spline}(x)))^{2} \leq s (w(yspline(x)))2s

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),范围再大就不行了,毕竟插值的专长不在于预测

s>0:不强制通过所有点

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()

在这里插入图片描述

多维插值

常见用法

后面几个例子中其实比较麻烦的不是插值算法,而是生成数据,而自己常遇到的情况是数表都已经准备好了,直接插值就可以了。
比如拿到一个二维数表z,横坐标就是x索引,纵坐标就是y索引,进而直接用 interp2d 就可以了。

官方文档:scipy.interpolate.interp2d

from scipy import interpolate
f = interpolate.interp2d(x, y, z, kind='linear', copy=True, bounds_error=False, fill_value=None)  # 首先定义插值函数
z1 = f(x1,y1)   # 如果想插值得到 (x1,y1) 处的新数据,则带入f即可

interp2d()

二维插值仍然参考文章 如何使scipy.interpolate给出超出输入范围的外推结果?
使用的函数为interp2d()

scipy.interpolate.interp2d(x, y, z, kind='linear', copy=True, bounds_error=False, fill_value=None)

其中kind为可选项,包括{‘linear’, ‘cubic’, ‘quintic’},默认是‘linear’。

这里有几个注意事项:

  • 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.
  • The interpolator is constructed by bisplrep, with a smoothing factor of 0. If more control over smoothing is needed, bisplrep should be used directly.
  • The coordinates of the data points to interpolate xnew and ynew have to be sorted by ascending order. interp2d is legacy and is not recommended for use in new code. New code should use RegularGridInterpolator instead.

基本用法

例1

import numpy as np 
def func(x,y): 
    return (x+y)*np.exp(-5*(x**2+y**2)) 
x = np.linspace(-1,1,15)
y = np.linspace(-1,1,20)
xx,yy = np.mgrid[-1:1:20j,-1:1:15j]      # 注意这里维度的先后顺序和x、y相反,j代表数据个数
z = func(xx,yy)

from scipy import interpolate
func_inter = interpolate.interp2d(x,y,z,kind='cubic')

xnew = np.linspace(-1,1,100)
ynew = np.linspace(-1,1,100)
znew = func_inter(xnew,ynew)     #xnew, ynew是一维的,输出znew是二维的
xnew,ynew = np.mgrid[-1:1:100j,-1:1:100j]   #统一变成二维,便于下一步画图

import mpl_toolkits.mplot3d
import matplotlib.pyplot as plt
ax=plt.subplot(111,projection='3d')
ax.plot_surface(xnew,ynew,znew)
ax.scatter(xx,yy,z,c='r',marker='^')
plt.show()

mgrid和meshgrid生成数据的不同

首先注意,mgrid生成的是等差数列,这直接限制了其应用范围,而meshgrid可以是任意数组。
关于两个的用法与区别,可参见 https://blog.csdn.net/gsgbgxp/article/details/129534233

例1
使用 mgrid

import numpy as np
from scipy import interpolate

x = np.linspace(-5.01, 5.01, 30)
y = np.linspace(-5.01, 5.01, 40)
xx, yy = np.mgrid[-5.01:5.01:40j,-5.01:5.01:30j] 
z = np.sin(xx**2+yy**3)
f = interpolate.interp2d(x, y, z, kind='cubic')

import matplotlib.pyplot as plt

xnew = np.arange(-5.01, 5.01, 1e-2)
ynew = np.arange(-5.01, 5.01, 1e-2)
znew = f(xnew, ynew)

plt.plot(x, z[0, :], 'ro-', xnew, znew[0, :], 'b-')
plt.show()

运行结果为
在这里插入图片描述

例2
使用 meshgrid

import numpy as np
from scipy import interpolate

x = np.arange(-5.01, 5.01, 0.25)
y = np.arange(-5.01, 5.01, 0.15)
xx, yy = np.meshgrid(x, y)
z = np.sin(xx**2+yy**3)
f = interpolate.interp2d(x, y, z, kind='cubic')

import matplotlib.pyplot as plt

xnew = np.arange(-5.01, 5.01, 1e-2)
ynew = np.arange(-5.01, 5.01, 1e-2)
znew = f(xnew, ynew)

plt.plot(x, z[0, :], 'ro-', xnew, znew[0, :], 'b-')
plt.show()

运行结果为
在这里插入图片描述
例3
发现上面两个例子运行结果不一样,这和mgrid与meshgrid之间的逻辑差别有关。如果想要得到一样的结果,可以修改例2中的z函数表达式。

import numpy as np
from scipy import interpolate

x = np.arange(-5.01, 5.01, 0.25)
y = np.arange(-5.01, 5.01, 0.15)
xx, yy = np.meshgrid(x, y)
z = np.sin(xx**3+yy**2)
f = interpolate.interp2d(x, y, z, kind='cubic')

import matplotlib.pyplot as plt

xnew = np.arange(-5.01, 5.01, 1e-2)
ynew = np.arange(-5.01, 5.01, 1e-2)
znew = f(xnew, ynew)

plt.plot(x, z[0, :], 'ro-', xnew, znew[0, :], 'b-')
plt.show()

运行结果为
在这里插入图片描述

生成间隔不均匀的数据并插值

mgrid只能生成间隔均匀的数据,因此需要采用meshgrid

# 如果x和y间隔不均匀-meshgrid形式

import numpy as np
from scipy import interpolate

x_start = 0
x_stop  = 5
x_num   = 10
x_base  = 1.5
y_start = 0
y_stop  = 5
y_num   = 10
y_base  = 1.5

x = np.logspace(x_start,x_stop,x_num,base=x_base)    # logspace生成等比数列,底为base
y = np.logspace(y_start,y_stop,y_num,base=y_base)
xx, yy = np.meshgrid(x, y)
z = np.sin(xx**2+yy**3)
f = interpolate.interp2d(x, y, z, kind='cubic')

import matplotlib.pyplot as plt

xnew = np.arange(x_base**x_start,x_base**x_stop, 1e-2)
ynew = np.arange(y_base**y_start,y_base**y_stop, 1e-2)
znew = f(xnew, ynew)

plt.plot(x, z[0, :], 'ro-', xnew, znew[0, :], 'b-')
plt.show()

运行结果为
在这里插入图片描述

二维插值Rbf()

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()

官方推荐函数:interpn 与 RegularGridInterpolator

还没详细研究,如果将来用到高维插值的话再看吧。
官方文档

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值