Algorithm 薄板样条插值实现的结果取决于自变量

Algorithm 薄板样条插值实现的结果取决于自变量,algorithm,python-3.x,interpolation,Algorithm,Python 3.x,Interpolation,我实现了该算法(另请参见),以便使用Python对分散的数据进行插值 当初始散乱数据的边界框的纵横比接近1时,我的算法似乎工作正常。但是,缩放其中一个数据点坐标会更改插值结果。我创建了一个最小的工作示例,它代表了我正在努力实现的目标。下面是显示50个随机点插值结果的两个图 首先,在域x=[0,3],y=[0120]上插入z=x^2: 如您所见,插值失败。现在,执行相同的过程,但将x值缩放40倍后,我得到: 这一次,结果看起来更好。选择稍有不同的比例因子将导致稍有不同的插值。这表明我的算法有问

我实现了该算法(另请参见),以便使用Python对分散的数据进行插值

当初始散乱数据的边界框的纵横比接近1时,我的算法似乎工作正常。但是,缩放其中一个数据点坐标会更改插值结果。我创建了一个最小的工作示例,它代表了我正在努力实现的目标。下面是显示50个随机点插值结果的两个图

首先,在域
x=[0,3],y=[0120]
上插入
z=x^2

如您所见,插值失败。现在,执行相同的过程,但将
x
值缩放40倍后,我得到:

这一次,结果看起来更好。选择稍有不同的比例因子将导致稍有不同的插值。这表明我的算法有问题,但我找不到确切的原因。以下是算法:

import numpy as np
import numba as nb

# pts1 = Mx2 matrix (original coordinates)
# z1   = Mx1 column vector (original values)
# pts2 = Nx2 matrix (interpolation coordinates)

def gen_K(n, pts1):
    K = np.zeros((n,n))

    for i in range(0,n):
        for j in range(0,n):
            if i != j:
                r = ( (pts1[i,0] - pts1[j,0])**2.0 + (pts1[i,1] - pts1[j,1])**2.0 )**0.5
                K[i,j] = r**2.0*np.log(r)

    return K

def compute_z2(m, n, pts1, pts2, coeffs):   
    z2 = np.zeros((m,1))

    x_min = np.min(pts1[:,0])
    x_max = np.max(pts1[:,0])
    y_min = np.min(pts1[:,1])
    y_max = np.max(pts1[:,1])

    for k in range(0,m):
        pt = pts2[k,:]

        # If point is located inside bounding box of pts1
        if (pt[0] >= x_min and pt[0] <= x_max and pt[1] >= y_min and pt[1] <= y_max):
            z2[k,0] = coeffs[-3,0] + coeffs[-2,0]*pts2[k,0] + coeffs[-1,0]*pts2[k,1]

            for i in range(0,n):
                r2 = ( (pts1[i,0] - pts2[k,0])**2.0 + (pts1[i,1] - pts2[k,1])**2.0 )**0.5

                if r2 != 0:
                    z2[k,0] += coeffs[i,0]*( r2**2.0*np.log(r2) )

        else:
            z2[k,0] = np.nan

    return z2

gen_K_nb = nb.jit(nb.float64[:,:](nb.int64, nb.float64[:,:]), nopython = True)(gen_K)
compute_z2_nb = nb.jit(nb.float64[:,:](nb.int64, nb.int64, nb.float64[:,:], nb.float64[:,:], nb.float64[:,:]), nopython = True)(compute_z2)

def TPS(pts1, z1, pts2, factor):
    n, m = pts1.shape[0], pts2.shape[0]

    P = np.hstack((np.ones((n,1)),pts1))
    Y = np.vstack((z1, np.zeros((3,1))))

    K = gen_K_nb(n, pts1)
    K += factor*np.identity(n)

    L = np.zeros((n+3,n+3))
    L[0:n, 0:n] = K
    L[0:n, n:n+3] = P
    L[n:n+3, 0:n] = P.T

    L_inv = np.linalg.inv(L)
    coeffs = L_inv.dot(Y)

    return compute_z2_nb(m, n, pts1, pts2, coeffs)

薄板样条曲线是标量不变的,这意味着如果用相同的因子缩放x和y,结果应该是相同的。但是,如果缩放x和y的方式不同,则结果将不同。这是径向基函数的共同特征。有些径向基函数甚至不是标量不变的

当你说它“失败”时,你是什么意思?最大的问题是,它是否仍然精确地在构造点处插值?假设您的代码是正确的,并且您没有病态,那么它应该不会失败

我认为正在发生的是,添加比例使
x
方向上的行为更具主导性,因此您不会看到插值自然产生的摆动

另外,通过矢量化,您可以大大加快代码的速度,而无需使用Numba

import scipy.spatial.distance
import scipy.special
def gen_K(n,pts1):
    # No need for n but kept to maintain compatability
    pts1 = np.atleast_2d(pts1)
    r = scipy.spatial.distance.cdist(pts1,pts1)
    return scipy.special.xlogy(r**2,r)
import scipy.spatial.distance
import scipy.special
def gen_K(n,pts1):
    # No need for n but kept to maintain compatability
    pts1 = np.atleast_2d(pts1)
    r = scipy.spatial.distance.cdist(pts1,pts1)
    return scipy.special.xlogy(r**2,r)