scipy 0.11.0到0.12.0更改了一个线性的scipy.interpolate.interp1d,打破了我不断更新的插值器

时间:2013-07-05 20:57:18

标签: python scipy ode interpolation

我一直在玩一个使用线性scipy.interpolate.interp1d的软件包来为scipy中的ode求解器创建一个历史函数,描述为here.

代码的相关部分类似于

def update(self, ti, Y):
        """ Add one new (ti, yi) to the interpolator """
        self.itpr.x = np.hstack([self.itpr.x,  [ti]])
        yi = np.array([Y]).T
        self.itpr.y = np.hstack([self.itpr.y,  yi])
        #self.itpr._y = np.hstack([self.itpr.y,  yi])
        self.itpr.fill_value = Y

在__init __:

中初始化“self.itpr”
def __init__(self, g, tc=0):
    """ g(t) = expression of Y(t) for t<tc """

    self.g = g
    self.tc = tc
    # We must fill the interpolator with 2 points minimum
    self.itpr = scipy.interpolate.interp1d(
        np.array([tc-1, tc]),  # X
        np.array([self.g(tc), self.g(tc)]).T,  # Y
        kind='linear',  bounds_error=False, 
        fill_value = self.g(tc))

其中g是一个函数,它返回一组值,这些值是一组微分方程的解,而tc是当前时间。

这对我来说很好,因为每次我想更新值的范围时都不需要重新创建新的插值器对象(在模拟期间的每个显式时间步骤都会发生)。这种更新插值器的方法在scipy v 0.11.0下运行良好。但是,在更新到v 0.12.0后,我遇到了问题。我看到新插值器现在包含一个数组_y,它似乎只是原始的另一个副本。如上所述,仅更新_y是否安全和/或明智? 是否有更简单,更pythonic的方式来解决这个问题,希望对scipy的未来更新更加强大?再次,在v 0.11中,一切运行良好并且预期结果产生,并且在0.12中得到一个IndexError when _y is referenced,因为它在我的函数中没有更新,而y本身就是。

任何帮助/指示都将不胜感激!

1 个答案:

答案 0 :(得分:3)

看起来_y只是由y重新整形的interp1d._reshape_yi()副本。因此,使用以下方法更新它应该是安全的:

  self.itpr._y = self.itpr._reshape_yi(self.itpr.y)

事实上,据我所知,只有_y被内插器内部使用,所以我认为你可以在没有实际更新y的情况下逃脱。

更优雅的解决方案是使_y为插值器的属性,返回y的适当重新整形的副本。可以通过在创建interp1d之后修改特定的x = np.arange(100) y = np.random.randn(100) itpr = interp1d(x,y) # method to get self._y from self.y def get_y(self): return self._reshape_yi(self.y) meth = property(get_y,doc='reshaped version of self.y') # make this a method of this interp1d instance only basecls = type(itpr) cls = type(basecls.__name__, (basecls,), {}) setattr(cls, '_y', meth) itpr.__class__ = cls # itpr._y is just a reshaped version of itpr.y print itpr.y.shape,itpr._y.shape >>> (100,) (100, 1) 实例来实现此目的(请参阅Alex Martelli的回答here以获得更多解释):

itpr._y

更新itpr.y

后,itpr.x = np.arange(110) itpr.y = np.random.randn(110) print itpr._y.shape >>> (110,) (110, 1) 现已更新
interp1d.__init__()

这一切都非常繁琐而且不是非常Pythonic - 修复scipy源代码(scipy / interpolate / interpolate.py)要容易得多。您需要做的就是从self._y = y 中删除最后一行:

@property
def _y(self):
    return self._reshape_yi(self.y)

并添加以下行:

{{1}}