Python/Scipy 二维插值(非均匀数据)

18 投票
1 回答
37046 浏览
提问于 2025-04-16 12:41

这是我之前帖子的问题的后续:Python/Scipy 插值 (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()

1 个回答

19

看起来你已经明白了。

在你上面的代码示例和你之前提到的(链接)问题中,你有的是结构化数据。这种数据可以用 RectBivariateSplineinterp2d 来进行插值。这意味着你的数据可以在一个网格上描述(网格上的所有点都有已知的值)。这个网格的每个点之间的距离(dx和dy)不一定要相同。如果所有的dx和dy都相等,那就是一个规则网格。

现在,你当前的问题是,如果不是所有的点都有已知值,该怎么处理。这种情况被称为非结构化数据。你只有一些选定的点,无法构建出所有角点都有已知值的矩形。对于这种数据,你可以使用(正如你所做的)griddata,或者某种形式的 BivariateSpline

那么该选择哪种呢?

与结构化的 RectBivariateSpline 最接近的非结构化 BivariateSpline 类别是 SmoothBivariateSplineLSQBivariateSpline。如果你想用样条插值数据,可以选择这些。这会让你的函数变得光滑且可微分,但可能会出现超出 Z.max() 或 Z.min() 的情况。

因为你设置了 ky=1kx=1,并且我相信你得到的只是对结构化数据的线性插值,我个人建议你可以从 RectBivariateSpline 切换到 interp2d 这个结构化网格插值方案。我知道文档上说它是用于 规则网格,但文档中的示例实际上是结构化的,而不是规则的。

如果你真的切换了方法,我很好奇你是否发现了两者之间的显著差异。欢迎使用 SciPy。

撰写回答