4

我一直在玩一个包,它使用线性 scipy.interpolate.interp1d 为 scipy 中的 ode 求解器创建历史函数,在此处描述。

相关的代码类似于

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

其中“self.itpr”在 __init__ 中初始化:

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))

whereg是一些函数,它返回一组值,这些值是一组微分方程的解,并且tc是当前时间。

这对我来说似乎很好,因为每次我想更新值的范围时都不必重新创建一个新的插值器对象(这发生在模拟期间的每个显式时间步)。这种更新插值器的方法在 scipy v 0.11.0 下运行良好。但是,在更新到 v 0.12.0 后,我遇到了问题。我看到新的插值器现在包含一个_y似乎只是原始的另一个副本的数组。_y如上所述 进行更新是否安全和/或理智?是否有一种更简单、更 Pythonic 的方法来解决这个问题,希望对 scipy 中的未来更新更加健壮? 同样,在 v 0.11 中一切正常并产生了预期的结果,在 v 0.12 中我得到了一个IndexError when_y被引用因为它没有在我的函数中更新,而 y 本身是。

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

4

1 回答 1

3

看起来_y只是一个y被 改造过的副本interp1d._reshape_yi()。因此,使用以下方法更新它应该是安全的:

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

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

一个更优雅的解决方案是创建_y一个内插器的属性,该属性返回一个适当重塑的y. 可以通过在创建后对您的特定实例进行猴子修补来实现这一点有关更多解释,interp1d请参见 Alex Martelli 的答案):

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)

现在itpr._y会在您更新时更新itpr.y

itpr.x = np.arange(110)
itpr.y = np.random.randn(110)
print itpr._y.shape
>>> (110,) (110, 1)

这一切都很繁琐,而且不是很 Pythonic - 修复 scipy 源代码 (scipy/interpolate/interpolate.py) 要容易得多。您需要做的就是从interp1d.__init__()它设置的位置删除最后一行:

self._y = y

并添加这些行:

@property
def _y(self):
    return self._reshape_yi(self.y)
于 2013-07-09T12:19:46.157 回答