Python/Scipy 2D 插值(非均匀数据)

Posted

技术标签:

【中文标题】Python/Scipy 2D 插值(非均匀数据)【英文标题】:Python/Scipy 2D Interpolation (Non-uniform Data) 【发布时间】:2011-07-05 23:38:55 【问题描述】:

这是我之前帖子的后续问题:Python/Scipy Interpolation (map_coordinates)

假设我想在二维矩形区域上进行插值。我的变量“z”包含如下所示的数据。每一列都是一个常数值,但是,数组的每一行可能是不同的值,如下面的注释所示。

from scipy import interpolate
from numpy import array
import numpy as np
#                                               # 0.0000, 0.1750, 0.8170, 1.0000
z = array([[-2.2818,-2.2818,-0.9309,-0.9309],   # 0.0000, 0.0000, 0.0000, 0.0000
           [-2.2818,-2.2818,-0.9309,-0.9309],   # 0.2620, 0.2784, 0.3379, 0.3526
           [-1.4891,-1.4891,-0.5531,-0.5531],   # 0.6121, 0.6351, 0.7118, 0.7309
           [-1.4891,-1.4891,-0.5531,-0.5531]])  # 1.0000, 1.0000, 1.0000, 1.0000
# Rows, Columns = z.shape

cols = array([0.0000, 0.1750, 0.8170, 1.0000])
rows = array([0.0000, 0.2620, 0.6121, 1.0000])

sp = interpolate.RectBivariateSpline(rows, cols, z, kx=1, ky=1, s=0)

xi = np.array([0.00000, 0.26200, 0.27840, 0.33790, 0.35260, 0.61210, 0.63510,
               0.71180, 0.73090, 1.00000], dtype=np.float)
yi = np.array([0.000, 0.167, 0.815, 1.000], dtype=np.float)
print sp(xi, yi)

作为另一种可视化方式,我知道的值数组是:

rows = array([0.0000, 0.2620, 0.2784, 0.3379, 0.3526,
                      0.6121, 0.6351, 0.7118, 0.7309, 1.0000])
#          # 0.0000, 0.1750, 0.8170, 1.0000
z = array([[-2.2818,-2.2818,-0.9309,-0.9309],   # 0.0000
           [-2.2818,      ?,      ?,      ?],   # 0.2620,
           [      ?,-2.2818,      ?,      ?],   # 0.2784
           [      ?,      ?,-0.9309,      ?],   # 0.3379
           [      ?      ,?,      ?,-0.9309],   # 0.3526
           [-1.4891,      ?,      ?,      ?],   # 0.6121
           [      ?,-1.4891,      ?,      ?],   # 0.6351
           [      ?,      ?,-0.5531,      ?],   # 0.7118
           [      ?,      ?,      ?,-0.5531],   # 0.7309
           [-1.4891,-1.4891,-0.5531,-0.5531]])  # 1.0000

我不知道'?'值,它们应该被插值。我尝试用 None 替换它们,但我的所有结果都得到了 'nan'。

编辑:

我想我需要使用“griddata”或“interp2”。 griddata 似乎产生了我期望的结果,但 'interp2' 没有。

from scipy import interpolate
from numpy import array
import numpy as np

z = array([[-2.2818,-2.2818,-0.9309,-0.9309],
           [-2.2818,-2.2818,-0.9309,-0.9309],
           [-1.4891,-1.4891,-0.5531,-0.5531],
           [-1.4891,-1.4891,-0.5531,-0.5531]])

rows = array([0.0000, 0.0000, 0.0000, 0.0000,
              0.2620, 0.2784, 0.3379, 0.3526,
              0.6121, 0.6351, 0.7118, 0.7309,
              1.0000, 1.0000, 1.0000, 1.0000])

cols = array([0.0000, 0.1750, 0.8180, 1.0000,
              0.0000, 0.1750, 0.8180, 1.0000,
              0.0000, 0.1750, 0.8180, 1.0000,
              0.0000, 0.1750, 0.8180, 1.0000])

xi = array([0.0000, 0.2620, 0.2784, 0.3379, 0.3526, 0.6121, 0.6351, 0.7118,
               0.7309, 1.0000], dtype=np.float)
yi = array([0.000, 0.175, 0.818, 1.000], dtype=np.float)

GD = interpolate.griddata((rows, cols), z.ravel(),
                          (xi[None,:], yi[:,None]), method='linear')
I2 = interpolate.interp2d(rows, cols, z, kind='linear')

print GD.reshape(4, 10).T
print '\n'
print I2(xi, yi).reshape(4, 10).T

import matplotlib.pyplot as plt
import numpy.ma as ma

plt.figure()
GD = interpolate.griddata((rows.ravel(), cols.ravel()), z.ravel(),
                          (xi[None,:], yi[:,None]), method='linear')
CS = plt.contour(xi,yi,GD,15,linewidths=0.5,colors='k')
CS = plt.contourf(xi,yi,GD,15,cmap=plt.cm.jet)
plt.colorbar()
plt.scatter(rows,cols,marker='o',c='b',s=5)

plt.figure()
I2 = I2(xi, yi)
CS = plt.contour(xi,yi,I2,15,linewidths=0.5,colors='k')
CS = plt.contourf(xi,yi,I2,15,cmap=plt.cm.jet)
plt.colorbar()
plt.scatter(rows,cols,marker='o',c='b',s=5)
plt.show()

【问题讨论】:

interp2 不会在非结构化或非线性数据上给出预期结果。正如文档docs.scipy.org/doc/scipy/reference/interpolate.html 中所说,它用于结构化数据。它甚至可以说它适用于更具限制性的常规(结构化)网格。我不相信,因为interp2d__doc__ 有一个使用直线(结构化,非规则)网格的示例。我详细阐述了我的答案,试图使这一点尽可能清晰,包括对结构化、非结构化和常规网格的明确定义。 【参考方案1】:

看起来你明白了。

在您上面的代码示例和您之前的 (linked) 问题中,您有 结构化 数据。可以使用RectBivariateSplineinterp2d 进行插值。这意味着您拥有可以在网格上描述的数据(网格上的所有点都有一个已知值)。网格不一定必须具有相同的 dx 和 dy。 (如果所有 dx's 和 dy's 相等,您将拥有一个常规网格)

现在,您当前的问题是,如果并非所有要点都已知,该怎么办。这称为非结构化数据。您所拥有的只是一个字段中的点选择。您不一定要构造所有顶点都具有已知值的矩形。对于这种类型的数据,您可以使用(如您所愿)griddata,或 BivariateSpline 的风格。

现在该选哪个?

与结构化 RectBivariateSpline 最接近的类比是 非结构化 BivariateSpline classes:SmoothBivariateSplineLSQBivariateSpline 之一。如果您想使用样条插值数据,请使用这些。这使您的函数平滑且可微,但您可以获得一个在 Z.max() 或 Z.min() 之外摆动的表面。

由于您正在设置 ky=1kx=1 并且得到我很确定的只是 结构化 数据的线性插值,我个人只是从 RectBivariateSpline 样条曲线切换方案到interp2d 结构化 网格插值方案。我知道文档说它适用于regular grids,但__doc__ 中的示例本身只是结构化,而不是常规的。

如果您最终切换时发现这些方法之间是否存在任何显着差异,我会很好奇。欢迎使用 SciPy。

【讨论】:

使用 interp2d 代替 griddata 有优势吗?似乎他们基本上做同样的事情。我认为主要区别实际上只是对于griddata,您提供您想要的信息并获得结果数组。对于 interp2d,我认为您会返回一个 interp 类,然后您可以使用它在任何点进行插值。这本质上是唯一的区别吗? 我发布了另一个比较这两种方法的答案。 我删除了我之前可能具有误导性的评论。 interp2dgriddata 不能总是互换使用。 interp2d 仅适用于直线数据(如果您相信文档,可能仅适用于常规数据)。 griddatainterp2d 对于这些限制性网格应该给出相同的结果。具有边不平行的单元格的网格不应与interp2d 一起使用。 interp2d 甚至允许输入与 z 形状相同的 x 和 y 数组,这很麻烦。 感谢保罗的所有帮助。现在很清楚了。我还发现它在提供 interp2d 非结构化数据时不会引发一些警告或错误,这很令人不安。 如何使用结构化方法处理 NaN 值,尤其是对于大型数组?

以上是关于Python/Scipy 2D 插值(非均匀数据)的主要内容,如果未能解决你的问题,请参考以下文章

Python scipy.interpolate插值

Python/scipy 中的一维非最大抑制

Python SciPy库——拟合与插值

Python SciPy库——拟合与插值

Python SciPy库——拟合与插值

如果我想要随机非结构化数据的 3D 样条/平滑插值怎么办?