【问题标题】:Invert interpolation to give the variable associated with a desired interpolation function value反转插值以给出与所需插值函数值相关的变量
【发布时间】:2021-12-07 06:52:36
【问题描述】:

我正在尝试使用 scipy 的插值函数反转插值函数。假设我创建了一个插值函数,

import scipy.interpolate as interpolate
interpolatedfunction = interpolated.interp1d(xvariable,data,kind='cubic')

当我指定a时是否有一些函数可以找到x:

interpolatedfunction(x) == a

换句话说,“我希望我的插值函数等于 a;xvariable 的值是多少,这样我的函数等于 a?”

我很感激我可以使用一些数值方案来做到这一点,但是有没有更直接的方法?如果插值函数在xvariable中是多值的呢?

【问题讨论】:

  • 所以你想要xinterpolatedfunction(x) == a
  • 没错。有没有内置函数可以做这样的事情?

标签: python scipy interpolation


【解决方案1】:

创建插值函数interp_fn后,可以通过函数的根找到x的值,其中interp_fn(x) == a

interp_fn2 = lambda x: interp_fn(x) - a

有许多选项可以在scipy.optimize 中找到根。例如,使用牛顿法,初始值从 10 开始:

from scipy import optimize

optimize.newton(interp_fn2, 10)

实际示例

创建一个插值函数,然后找到fn(x) == 5的根

import numpy as np
from scipy import interpolate, optimize

x = np.arange(10)
y = 1 + 6*np.arange(10) - np.arange(10)**2
y2 = 5*np.ones_like(x)
plt.scatter(x,y)
plt.plot(x,y)
plt.plot(x,y2,'k-')
plt.show()

# create the interpolated function, and then the offset
# function used to find the roots

interp_fn = interpolate.interp1d(x, y, 'quadratic')
interp_fn2 = lambda x: interp_fn(x)-5

# to find the roots, we need to supply a starting value
# because there are more than 1 root in our range, we need 
# to supply multiple starting values.  They should be 
# fairly close to the actual root

root1, root2 = optimize.newton(interp_fn2, 1), optimize.newton(interp_fn2, 5)

root1, root2
# returns:
(0.76393202250021064, 5.2360679774997898)

【讨论】:

    【解决方案2】:

    有一些专门的方法可以找到三次样条的根。最简单的使用是InterpolatedUnivariateSpline对象的.roots()方法:

    spl = InterpolatedUnivariateSpline(x, y)
    roots = spl.roots()
    

    这会找到所有根,而不仅仅是一个,就像通用求解器(fsolvebrentqnewtonbisect 等)所做的那样。

    x = np.arange(20)
    y = np.cos(np.arange(20))
    spl = InterpolatedUnivariateSpline(x, y)
    print(spl.roots())
    

    输出array([ 1.56669456, 4.71145244, 7.85321627, 10.99554642, 14.13792756, 17.28271674])

    但是,您希望将样条曲线等同于某个任意数字 a,而不是 0。一种选择是重建样条曲线(您不能只从中减去 a):

    solutions = InterpolatedUnivariateSpline(x, y - a).roots()
    

    请注意,这些都不适用于interp1d 返回的函数;它没有roots 方法。对于该函数,可以选择使用诸如fsolve 之类的通用方法,但您一次只能从中获得一个根。无论如何,既然有更强大的方法来执行相同类型的插值,为什么还要将interp1d 用于三次样条?

    非面向对象的方式

    可以直接从样条系数中减去a,而不是在从数据中减去a 后重建样条。这需要我们使用非面向对象的插值方法。具体来说,sproot 接受splrep 准备的一个 tck 元组,如下:

    tck = splrep(x, y, k=3, s=0)
    tck_mod = (tck[0], tck[1] - a, tck[2])
    solutions = sproot(tck_mod)    
    

    我不确定与tck 混淆是否值得在这里获得收益,因为无论如何大部分计算时间都可能用于寻根。但最好有替代品。

    【讨论】:

    • 作为 .roots() 的优秀替代品可以找到所有的根(如果它们存在的话)。
    【解决方案3】:

    如果您的数据是单调的,您还可以尝试以下方法:

    inversefunction = interpolated.interp1d(data, xvariable, kind='cubic')
    

    【讨论】:

    • 这太棒了。对于从自定义分布中采样特别有用。
    猜你喜欢
    • 1970-01-01
    • 2014-09-03
    • 1970-01-01
    • 2018-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多