在Numpy / Scipy中逼近具有任意输入和输出维数的向量值多元函数

时间:2018-03-19 13:11:59

标签: numpy scipy interpolation taylor-series function-approximation

起始点是m维向量值函数

eq

其中输入也是n维向量:

eq

此函数的输入和输出是numpy向量。这个函数计算起来很昂贵,所以我需要一个近似/插值。

是否有numpy / scipy函数返回近似值,例如:泰勒扩展,该函数接近 x 的给定值,任意维 m,n

基本上,我要求概括 scipy.interpolate.approximate_taylor_polynomial ,因为我也对近似的二次项感兴趣。

scipy.interpolate 中,似乎有一些矢量值 x 选项,但仅适用于标量函数,但只是循环遍历函数的m个组件不是一个选项,因为组件不能单独计算,而且函数的调用次数会超出必要的范围。

如果不存在这样的函数,使用现有方法并避免不必要的函数调用的快速方法也会很棒。

1 个答案:

答案 0 :(得分:1)

我认为你必须为此推出自己的近似值。这个想法很简单:在一些合理的点上对函数进行采样(至少与泰勒近似中的单项式一样多,但最好更多),并使系数与np.linalg.lstsq拟合。实际的拟合是一行,其余的是准备它。

我将使用n = 3且m = 2的示例,因此有三个变量和二维值。初始设置:

import numpy as np
def f(point):
  x, y, z = point[0], point[1], point[2]
  return np.array([np.exp(x + 2*y + 3*z), np.exp(3*x + 2*y + z)]) 
n = 3
m = 2
scale = 0.1

scale参数的选择与approximate_taylor_polynomial的文档字符串中的注意事项相同(请参阅source)。

下一步是产生积分。对于n个变量,二次拟合涉及1 + n + n*(n+1)/2单项式(一个常数,n个线性,n(n + 1)/ 2个二次)。我使用放置在1 + n + n**2周围的(0, 0, 0)个点,并且有一个或两个非零坐标。特定的选择有点武断;我找不到一个"规范"多元二次拟合的样本点选择。

points = [np.zeros((n, ))]
points.extend(scale*np.eye(n))
for i in range(n):
    for j in range(n):
        point = np.zeros((n,))
        point[i], point[j] = scale, -scale
        points.append(point)
points = np.array(points)
values = f(points.T).T

数组values包含每个点的函数值。前一行是调用f的唯一位置。下一步,为模型生成单项式,并在这些相同点进行评估。

monomials = [np.zeros((1, n)), np.eye(n)]
for i in range(n):
    for j in range(i, n):
        monom = np.zeros((1, n))
        monom[0, i] += 1
        monom[0, j] += 1
        monomials.append(monom)
monomials = np.concatenate(monomials, axis=0)
monom_values = np.prod(points**monomials[:, None, :], axis=-1).T

让我们回顾一下情况:我们在这里有values函数,形状(13,2),以及形状为单项式(13,10)。这里13是点数,10是单项数。对于values的每一列,lstsq方法将找到最接近它的monomials列的线性组合。这些是我们想要的系数。

coeffs = np.linalg.lstsq(monom_values, values, rcond=None)[0]

让我们看看这些是否有用。系数

[[1.         1.        ]
 [1.01171761 3.03011523]
 [2.01839762 2.01839762]
 [3.03011523 1.01171761]
 [0.50041681 4.53385141]
 [2.00667556 6.04011017]
 [3.02759266 3.02759266]
 [2.00667556 2.00667556]
 [6.04011017 2.00667556]
 [4.53385141 0.50041681]]

和数组monomials,供参考,是

[[0. 0. 0.]
 [1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]
 [2. 0. 0.]
 [1. 1. 0.]
 [1. 0. 1.]
 [0. 2. 0.]
 [0. 1. 1.]
 [0. 0. 2.]]

因此,例如,编码为x**2的单项[2, 0, 0]获取函数[0.50041681 4.53385141]的两个分量的系数f。这是完全合理的,因为它在exp(x + 2*y + 3*z)的泰勒展开中的系数是0.5,而在exp(3*x + 2*y + z)的泰勒展开中它是4.5。

函数f的近似值可以通过

获得
def fFit(point,coeffs,monomials):
    return np.prod(point**monomials[:, None, :], axis=-1).T.dot(coeffs)[0]

testpoint = np.array([0.05,-0.05,0.0])

# true value:
print(f(testpoint)) # output: [ 0.95122942  1.0512711 ]

# approximation:
print(fFit(testpoint,coeffs,monomials)) # output: [ 0.95091704  1.05183692]