interpolate.griddata结果不一致

时间:2018-03-23 15:26:37

标签: python scipy interpolation

我正在将一些代码从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

2 个答案:

答案 0 :(得分:3)

我认为解释可能在于scipy.interpolate.griddata在插值之前构建数据三角化的方式。在文档中,这会使用scipy.interpolate.LinearNDInterpolator,它看起来像构建了Delaunay triangularization数据,当您在网格边缘添加更多节点时,这些数据不能保证相同(正如你已经完成了numpy.tile)。由于2D区域被划分为三角形的方式,因此生成的线性插值可能会有所不同。

对于普通的4x5网格,缺少(2,2)元素,scipy.spatial.Delaunay生成的Delaunay三角化看起来像这样: enter image description here

如果然后平铺网格数据,那么当你有四个网格副本时,Delaunay三角化在(2,2)位置周围发生变化,现在位于水平边界而不是垂直边界:

enter image description here

这意味着(2,2)处的值的结果插值将使用一组不同的相邻节点,这将在此扩展网格上给出不同的插值。 (从一些快速实验来看,这种效果可能不会出现2x或3x平铺,但会出现在4x平铺上。) 三角形布局的这种变化是由于计算Delaunay三角化的方式,其中包括将整个 2D网格投影到3D空间中,然后计算凸包然后将其投影回2D三角形。这意味着当您向网格添加更多节点时,即使它引用原始2D网格中的相同节点,也不能保证3D凸包将是相同的。

答案 1 :(得分:3)

Jaime's answer描述了scipy.interpolate.griddata如何使用Delaunay三角剖分插值:

  

[何时]您拨打scipy.interpolate.griddata

     
      
  1. 首先,调用sp.spatial.qhull.Delaunay来对不规则网格坐标进行三角测量。
  2.   
  3. 然后,对于新网格中的每个点,搜索三角测量以找到它所在的三角形。
  4.   
  5. 计算每个新网格点相对于封闭单形顶点的重心坐标。
  6.   
  7. 使用重心坐标计算该网格点的插值,以及封闭单形顶点处函数的值。
  8.   

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)

enter image description here

enter image description here

如您所见,两个插值(0.1995和0.073)是(AC)或(BD)的平均值(使用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