Python scipy.interpolate插值

Posted Windy.Zhhh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python scipy.interpolate插值相关的知识,希望对你有一定的参考价值。

我们采集到的数据都是以离散的点的形式存在的,只有在采样点上才有具体的值,在其他区域都没有值数据。此时就需要插值分析,将采样点的数值根据一定的算法,推算出其他未采样区域的数值。

在讲scipy.interpolate类方法插值函数之前我们先讲两种常见的插值方法:待定系数法和拉格朗日法插值。

待定系数法插值:待定系数法插值在我们拥有n个插值节点时构造一个n次多项式,

 然后可以构造非齐次线性方程组,

 在高数或线性代数里,我们学过范德蒙德行列式,我们可以根据上述非齐次线性方程组构造出它的系数矩阵,

再根据解线性方程组的克拉默(克莱姆) 法则,线性方程组的解确定且唯一,由此我们便可以得到我们的插值函数。

由python代码编写如下:

import numpy as np
import matplotlib.pyplot as plt
from scipy import interpolate
x0=np.linspace(-10,10,21)
y0=np.sin(x0)
plt.plot(x0,y0,'o')
A=np.vander(x0)
p=np.linalg.inv(A)@y0
x1=np.linspace(-10,10,101)
plt.plot(x1,np.polyval(p,x1))

 拉格朗日插值法:相对于待定系数法更为简便,首先构造一组基函数,

并令其满足以下条件,

得到n次拉格朗日插值多项式,由方程组

解的唯一性,n+1个节点的n次拉格朗日插值多项式存在且唯一。

python实现代码如下:

import numpy as np
from scipy import interpolate
import pylab as pl
x=np.linspace(-15,15,11)
y=np.sin(x)
pl.plot(x,y,'o')
x1=np.linspace(-15,15,101)
p=interpolate.lagrange(x,y)
pl.plot(x1,np.polyval(p,x1))

 

此外还要注意当插值次数太高产生的龙格现象。龙格现象_百度百科在计算方法中,有利用多项式对某一函数的近似逼近,计算相应的函数值。一般情况下,多项式的次数越多,需要的数据就越多,而预测也就越准确。插值次数越高,插值结果越偏离原函数的现象称为龙格现象。https://baike.baidu.com/item/%E9%BE%99%E6%A0%BC%E7%8E%B0%E8%B1%A1/5473475

import numpy as np
import matplotlib.pyplot as plt
from scipy import interpolate
x=np.linspace(-10,10,11)
y=np.sin(x)
x1=np.linspace(-10,10,101)
y1=np.sin(x1)
plt.plot(x1,y1,label='sinx')
f1=interpolate.interp1d(x,y,kind='quadratic')
f2=interpolate.interp1d(x,y,kind='cubic')
f3=interpolate.interp1d(x,y,kind=7)
f4=interpolate.interp1d(x,y,kind=9)
plt.plot(x1,f1(x1),label='2')
plt.plot(x1,f2(x1),label='3')
plt.plot(x1,f3(x1),label='5')
plt.plot(x1,f4(x1),label='9')
plt.legend()
plt.show()

 现在我们开始讲scipy.interpolate类函数插值方法

一维插值:使用interpolate.interp1d函数插值

官方文档:

scipy.interpolate.interp1d — SciPy v1.8.1 Manual

使用时主要定义kind的类型来进行不同类别的插值

一次插值kind='inear'

二次插值kind='quadratic'

三次插值kind='cubic'

此外还有0阶插值nearest和zero方法

此两种方法使用如下:

import numpy as np
from scipy import interpolate
import matplotlib.pyplot as plt
x=np.linspace(0,10,11)
y=np.sin(x)
x1=np.linspace(0,10,101)
y1=np.sin(x1)
plt.plot(x1,y1)
f1=interpolate.interp1d(x,y,kind='nearest')
plt.plot(x1,f1(x1))
f2=interpolate.interp1d(x,y,kind='zero')
plt.plot(x1,f2(x1))
plt.plot(x,y)

可构成阶梯状曲线

 二维插值:使用interpolate.interp2d函数插值

对模糊图像处理:

示例函数如下:

import numpy as np
import matplotlib as mpl
import pylab as pl
from scipy import interpolate

def z(x,y):
    return (x+y)*np.exp(-5*(x**2+y**2))
x,y=np.mgrid[-1:1:15j,-1:1:15j]
newfunc=interpolate.interp2d(x,y,z(x,y),kind='cubic')
xnew=np.linspace(-1,1,200)
ynew=np.linspace(-1,1,200)
fnew=newfunc(xnew,ynew)
pl.subplot(121)
im1=pl.imshow(z(x,y),origin='lower',extent=[-1,1,-1,1],cmap=mpl.cm.hot)
pl.colorbar(im1)
pl.subplot(122)
im2=pl.imshow(fnew,origin='lower',extent=[-1,1,-1,1],cmap=mpl.cm.hot)
pl.colorbar(im2)
pl.show()

 二维插值的三维图片展示

函数仍未上示例函数

import numpy as np
import matplotlib as mpl
from scipy import interpolate
import matplotlib.pyplot as plt

def func(x, y):
    return (x + y) * np.exp(-5.0 * (x ** 2 + y ** 2))

x,y=np.mgrid[-1:1:20j,-1:1:20j]  
fvals = func(x, y)  
fig = plt.figure(figsize=(18,10))  
ax = plt.subplot(121, projection='3d')
surf = ax.plot_surface(x, y, fvals, rstride=1, cstride=1, cmap=mpl.cm.coolwarm, linewidth=0.5,
                       antialiased=True)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')  
plt.colorbar(surf, shrink=0.5, aspect=5,pad=0.1)  
newfunc = interpolate.interp2d(x, y, fvals, kind='cubic')  
xnew = np.linspace(-1, 1, 200) 
ynew = np.linspace(-1, 1, 200) 
fnew = newfunc(xnew, ynew)  
xnew, ynew = np.meshgrid(xnew, ynew)
ax2 = plt.subplot(122, projection='3d')
surf2 = ax2.plot_surface(xnew, ynew, fnew, rstride=1, cstride=1, cmap=mpl.cm.coolwarm, linewidth=0.5, antialiased=True)
ax2.set_xlabel('xnew')
ax2.set_ylabel('ynew')
ax2.set_zlabel('znew')
plt.colorbar(surf2, shrink=0.5, aspect=5,pad=0.1)  
plt.show()

差异 scipy interpolate vs mpl griddata

【中文标题】差异 scipy interpolate vs mpl griddata【英文标题】:differences scipy interpolate vs mpl griddata 【发布时间】:2021-12-31 22:15:36 【问题描述】:

我差点把头发扯下来,真的希望有人能在这里帮助我。

我需要将一个脚本从 python 2 转换为 python 3,它是一个简单的脚本,它接受坐标点xy,以及这些点的值z

z 在网格上插值,然后绘制。 python 2脚本中的插值目前正在使用from matplotlib.mlab import griddata

但是,python 3 中不存在 mlab griddata。所以我认为我们应该使用 scipy.interpolate 作为替代品。

问题是,它给了我非常奇怪的结果。

最近邻比较

Mpl griddata With interp='nn' 给我:

scipy interpolate using method='nearest' 给了我

这是最重要的,因为这是我需要的结果,但结果却如此不同!

我尝试了其他参数看看是否仍然存在

线性比较

带有interp='linear'的mpl griddata给了我

scipy interpolate with method='linear' 给了我

线性显示相同的结果,但我不在乎线性。

三次比较

mpl griddata 没有三次,但是使用 scipy interpolate 的结果非常奇怪。

数据

import numpy as np
# points
x = np.array([31132.71118116, 10763.66383076, 29340.62119857,  4025.2544491 ,
       19158.87683925, 36584.96725821, 17335.28090098, 27279.80878719,
        5893.32833709, 36392.22873482, 22350.16973122, 40235.86525991,
       19844.57893466, 11245.50791534, 17103.62528354, 29944.77964486,
       34021.92540595, 44485.36307614,  8797.36817447, 24733.44616607,
       30628.62812172, 27227.91858716, 26221.60497488, 27987.74985745,
       14366.37775758, 32035.24328142, 29779.84095199, 42821.14608703,
       42229.95963477, 22592.94483609, 26362.45107434, 22161.13844494,
       21562.53974235, 40784.42626907, 14195.87932099, 25628.56490406,
       19212.62065784, 28354.69294259, 34299.91259166, 28276.85653059,
       13291.49360218, 64014.88912569,     0.        , 64014.88912569,
           0.        ])
    
y = np.array([1.61640041e+04, 1.18226221e+04, 1.66496799e+04, 1.60268291e+04,
       1.47533260e+04, 1.72743862e+04, 2.58461610e+04, 1.11997818e+04,
       1.94747705e+04, 2.81559903e+04, 2.85786579e+04, 2.16418047e+04,
       2.58684064e+04, 2.17474690e+04, 3.21398453e+04, 2.13563269e+04,
       2.12339790e+04, 2.42537633e+04, 1.89242092e+04, 2.45410984e+04,
       1.90984612e+04, 2.45058762e+04, 1.76859142e+04, 2.13655953e+04,
       2.62595562e+04, 1.44826845e+04, 2.55328718e+04, 2.97076285e+04,
       1.81975446e+04, 3.27182416e+04, 1.88407910e+04, 1.58599943e+04,
       2.02514897e+04, 2.42723003e+04, 1.76265941e+04, 1.60045845e+04,
       2.03274941e+04, 1.67609034e+04, 1.74986867e+04, 1.78898244e+04,
       3.21546756e+04, 9.55042196e-08, 9.55042196e-08, 4.04414440e+04,
       4.04414440e+04])
    
z = np.array([0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0.6, 0. , 0. , 0. , 0. ,
       0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ,
       0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ,
       0. , 0. , 0. , 0. , 0. , 0. ])
    
min_grid_val_x = 0
max_grid_val_x = 64014.88912569069

min_grid_val_y = 9.550421964377165e-08
max_grid_val_y = 40441.443993242734
    
# set up a square grid with the same extents as our measured data
numcols, numrows = 1000, 1000
xi = np.linspace(min_grid_val_x, max_grid_val_x, numcols)
yi = np.linspace(min_grid_val_y, max_grid_val_y, numrows)
xi, yi = np.meshgrid(xi, yi)

其他代码


import numpy as np
import pandas as pd
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import matplotlib.colors as mc
import matplotlib.patches as mpatches
from matplotlib.colors import ListedColormap
from matplotlib.colors import Normalize
import math

MODE == 'mpl'
if MODE == 'mpl':
    from matplotlib.mlab import griddata
    zi = griddata(x, y, z, xi, yi, interp='nn')
else:
    from scipy.interpolate import griddata
    points = np.array([[x[i],y[i]] for i in range(len(x))])
    zi = griddata(points, z, (xi, yi), method='cubic',fill_value=0)
    
min_val = math.floor(z.min())
max_val = math.ceil(z.max())
resolutions = [0.1, 0.2, 0.5, 1, 1.5, 2, 3, 5, 10, 
               15, 20, 30, 40, 50, 60, 70, 80]
    
max_of_Z = z.max()
if (max_of_Z==0):
    levels = np.arange(min, min + (0.1 * 12), 0.1)
else:
    hit = False
    for res in resolutions:
        condition = res*12
        if condition > z.max():
            print("Using ".format(res))
            levels = np.arange(min_val, max_val + condition, res)
            hit = True
            break
    if not hit:
        res = 90
        print("Using ".format(res))
        condition = res*12
        levels = np.arange(min_val, max_val + condition, res)
    
norm = mc.BoundaryNorm(levels, len(levels)-1)

cmapV=ListedColormap([[0.73,0.90,0.97],
[0.66,0.87,0.97],
[0.57,0.82,0.95],
[0.49,0.76,0.91],
[0.40,0.69,0.87],
[0.32,0.62,0.83],
[0.26,0.53,0.77],
[0.20,0.44,0.71],
[0.14,0.34,0.64],
[0.13,0.29,0.56],
[0.12,0.23,0.47],
[0.11,0.17,0.38]])

# define map extent
lllat=1.1497
urlat=1.5133
lllon=103.5822
urlon=104.1579
# set up plot
plt.clf()
fig = plt.figure(figsize=(13, 6))
ax = fig.add_subplot(111, facecolor='w', frame_on=False)

# Set up Basemap instance
m = Basemap(
    projection = 'merc',
    llcrnrlon = lllon, llcrnrlat = lllat, urcrnrlon = urlon, urcrnrlat = urlat,
    resolution='h')

# contour plot
con = m.contourf(xi, yi, zi, zorder=1, alpha=None, cmap=cmapV, levels=levels, norm=norm)

【问题讨论】:

【参考方案1】:

根据STOQS 的问题Github 页面上的this discussion,最接近旧Matplotlib 的griddata 默认算法,即自然邻居,是使用scipy.interpolate.griddata 获得的与method='cubic'rescale=True

也就是说,如果您发布的数据代表了您的实际问题,那么您的图表都没有洞察力,因为您不应该从单个数据点 (x=5893.32833709, y=19474.7705, z=0.6) 进行推断,而所有其他数据点都有一个 z纵坐标全等于零。

【讨论】:

嘿,感谢您的回复!我以前看过那个帖子,它对我也不起作用。尝试griddata(points, z, (xi, yi), method='cubic',fill_value=0, rescale=True) 给了我与问题中最后一个情节几乎完全相同的情节。如果它只给出左上角的区域(即大多数点为 0),我会接受这个图。是的,这是真实数据,将是一种常见情况。这种情况下的预期结果是理想情况下的第一个图 (NN) @Wboy ①如果你在Q中提到你已经看过那个问题,我可能不会浪费时间回答②当你的数据有结构时,插值结果是明智的,尽管有算法;相反…… 抱歉浪费您的时间。我正在寻找一种在 python 3 中复制 mpl 的旧 griddata 自然邻居插值的方法。

以上是关于Python scipy.interpolate插值的主要内容,如果未能解决你的问题,请参考以下文章

函数 scipy.interpolate.interpn() 太慢了

scipy 0.11.0 到 0.12.0 更改了线性 scipy.interpolate.interp1d,破坏了我不断更新的插值器

如何使 scipy.interpolate 给出超出输入范围的推断结果?

使用scipy.interpolate.CubicSpline添加或乘以三次样条曲线

气象 python 二维线性插值

使用 scipy interpolate griddata 方法重新网格化数据时出现意外的内存错误