我正在将一些代码从Matlab转换为Python,并发现我从scipy.interpolate.griddata获得的结果与Matlab scatInterpolant不同。经过大量的研究和实验,我发现scipy.interpolate.griddata的插图结果似乎取决于所提供数据集的大小。似乎存在导致内插值改变的阈值。这是一个错误吗?或者有人可以解释导致这种情况的算法。以下是演示此问题的代码。
import numpy as np
from scipy import interpolate
# This code provides a simple example showing that the interpolated value
# for the same location changes depending on the size of the input data set.
# Results of this example show that the interpolated value changes
# at repeat 10 and 300.
def compute_missing_value(data):
"""Compute the missing value example function."""
# Indices for valid x, y, and z data
# In this example x and y are simply the column and row indices
valid_rows, valid_cols = np.where(np.isnan(data) == False)
valid_data = data[np.isnan(data) == False]
interpolated_value = interpolate.griddata(np.array((valid_rows,
valid_cols)).T, valid_data, (2, 2), method='linear')
print('Size=', data.shape,' Value:', interpolated_value)
# Sample data
data = np.array([[0.2154, 0.1456, 0.1058, 0.1918],
[-0.0398, 0.2238, -0.0576, 0.3841],
[0.2485, 0.2644, 0.2639, 0.1345],
[0.2161, 0.1913, 0.2036, 0.1462],
[0.0540, 0.3310, 0.3674, 0.2862]])
# Larger data sets are created by tiling the original data.
# The location of the invalid data to be interpolated is maintained at 2,2
repeat_list =[1, 9, 10, 11, 30, 100, 300]
for repeat in repeat_list:
new_data = np.tile(data, (1, repeat))
new_data[2,2] = np.nan
compute_missing_value(new_data)
结果是:
Size= (5, 4) Value: 0.07300000000000001 Size= (5, 36) Value: 0.07300000000000001 Size= (5, 40) Value: 0.19945000000000002 Size= (5, 44) Value: 0.07300000000000001 Size= (5, 120) Value: 0.07300000000000001 Size= (5, 400) Value: 0.07300000000000001 Size= (5, 1200) Value: 0.19945000000000002
答案 0 :(得分:3)
我认为解释可能在于scipy.interpolate.griddata在插值之前构建数据三角化的方式。在文档中,这会使用scipy.interpolate.LinearNDInterpolator,它看起来像构建了Delaunay triangularization数据,当您在网格边缘添加更多节点时,这些数据不能保证相同(正如你已经完成了numpy.tile)。由于2D区域被划分为三角形的方式,因此生成的线性插值可能会有所不同。
对于普通的4x5网格,缺少(2,2)元素,scipy.spatial.Delaunay生成的Delaunay三角化看起来像这样:
如果然后平铺网格数据,那么当你有四个网格副本时,Delaunay三角化在(2,2)位置周围发生变化,现在位于水平边界而不是垂直边界:
这意味着(2,2)处的值的结果插值将使用一组不同的相邻节点,这将在此扩展网格上给出不同的插值。 (从一些快速实验来看,这种效果可能不会出现2x或3x平铺,但会出现在4x平铺上。) 三角形布局的这种变化是由于计算Delaunay三角化的方式,其中包括将整个 2D网格投影到3D空间中,然后计算凸包然后将其投影回2D三角形。这意味着当您向网格添加更多节点时,即使它引用原始2D网格中的相同节点,也不能保证3D凸包将是相同的。
答案 1 :(得分:3)
Jaime's answer描述了scipy.interpolate.griddata
如何使用Delaunay三角剖分插值:
[何时]您拨打
scipy.interpolate.griddata
:
- 首先,调用sp.spatial.qhull.Delaunay来对不规则网格坐标进行三角测量。
- 然后,对于新网格中的每个点,搜索三角测量以找到它所在的三角形。
- 计算每个新网格点相对于封闭单形顶点的重心坐标。
- 使用重心坐标计算该网格点的插值,以及封闭单形顶点处函数的值。
醇>
pv.
explains德劳内
由正方形网格生成的三角测量不是唯一的。既然要点
根据三角测量得到线性插值,可以得到不同的
结果取决于特定的Delaunay三角剖分产生。
以下是您的脚本的修改版本,其中使用了Delaunay三叉树:
import numpy as np
from scipy import interpolate
import matplotlib.pyplot as plt
import scipy.spatial as spatial
import matplotlib.collections as mcoll
def compute_missing_value(data):
"""Compute the missing value example function."""
mask = ~np.isnan(data)
valid_rows, valid_cols = np.where(mask)
valid_data = data[mask]
interpolated_value = interpolate.griddata(
(valid_cols, valid_rows), valid_data, (2, 2), method='linear')
print('Size: {:<12s} Value: {:<.4f}'.format(
str(data.shape), interpolated_value))
points = np.column_stack((valid_cols, valid_rows))
tess = spatial.Delaunay(points)
tri = tess.simplices
verts = tess.points[tri]
lc = mcoll.LineCollection(
verts, colors='black', linewidth=2, zorder=5)
fig, ax = plt.subplots(figsize=(6, 6))
ax.add_collection(lc)
ax.plot(valid_cols, valid_rows, 'ko')
ax.set(xlim=(0, 3), ylim=(0, 3))
plt.title('Size: {:<12s} Value: {:<.4f}'.format(
str(data.shape), interpolated_value))
for label, x, y in zip(valid_data, valid_cols, valid_rows):
plt.annotate(
label,
xy=(x, y), xycoords='data',
xytext = (-20, -40), textcoords = 'offset points',
horizontalalignment = 'center',
verticalalignment = 'bottom',
bbox = dict(
boxstyle='round,pad=0.5', fc='yellow', alpha=0.5),
arrowprops = dict(arrowstyle='->', connectionstyle='arc3,rad=0'))
plt.show()
# Sample data
orig_data = np.array([[0.2154, 0.1456, 0.1058, 0.1918],
[-0.0398, 0.2238, -0.0576, 0.3841],
[0.2485, 0.2644, 0.2639, 0.1345],
[0.2161, 0.1913, 0.2036, 0.1462],
[0.0540, 0.3310, 0.3674, 0.2862]])
repeat_list =[1, 4]
for repeat in repeat_list:
print('{}: '.format(repeat), end='')
new_data = np.tile(orig_data, (1, repeat))
new_data[2,2] = np.nan
compute_missing_value(new_data)
如您所见,两个插值(0.1995和0.073)是(A
,C
)或(B
,D
)的平均值(使用pv.'s notation):
In [159]: (0.2644+0.1345)/2
Out[159]: 0.19945000000000002
In [160]: (0.2036-0.0576)/2
Out[160]: 0.07300000000000001