简体   繁体   English

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

[英]scipy 0.11.0 to 0.12.0 changes a linear scipy.interpolate.interp1d, breaks my constantly updated interpolator

I have been playing around with a package that uses a linear scipy.interpolate.interp1d to create a history function for the ode solver in scipy, described here. 我一直在玩一个使用线性scipy.interpolate.interp1d的软件包,为scipy中的ode求解器创建一个历史函数,如下所述

The relevant bit of code goes something like 相关的代码就像是

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

Where "self.itpr" is initialized in __init__: 其中“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))

Where g is some function that returns an array of values that are solutions to a set of differential equations and tc is the current time. 其中g是一些函数,它返回一组值,这些值是一组微分方程的解, tc是当前时间。

This seems nice to me because a new interpolator object doesn't have to be re-created every time I want to update the ranges of values (which happens at each explicit time step during a simulation). 这对我来说很好,因为每次我想要更新值的范围时都不需要重新创建新的插值器对象(在模拟期间的每个显式时间步骤中都会发生)。 This method of updating the interpolator works well under scipy v 0.11.0. 这种更新插值器的方法在scipy v 0.11.0下运行良好。 However, after updating to v 0.12.0 I ran into issues. 但是,在更新到v 0.12.0后,我遇到了问题。 I see that the new interpolator now includes an array _y that seems to just be another copy of the original. 我看到新插值器现在包含一个数组_y ,它似乎只是原始的另一个副本。 Is it safe and/or sane to just update _y as outlined above as well? 如上所述,仅更新_y是否安全和/或明智? Is there a simpler, more pythonic way to address this that would hopefully be more robust to future updates in scipy? 有没有更简单,更pythonic的方式来解决这个问题,希望对scipy的未来更新更加健壮? Again, in v 0.11 everything works well and expected results are produced, and in v 0.12 I get an IndexError when _y is referenced as it isn't updated in my function while y itself is. 同样,在v 0.11中,一切都运行良好并且产生了期望的结果,并且在v 0.12中, _y被引用时,我得到一个IndexError 因为它在我的函数中没有更新,而y本身就是。

Any help/pointers would be appreciated! 任何帮助/指针将不胜感激!

It looks like _y is just a copy of y that has been reshaped by interp1d._reshape_yi() . 看起来_y只是由interp1d._reshape_yi()重新整形的y的副本。 It should therefore be safe to just update it using: 因此,使用以下方法更新它应该是安全的:

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

In fact, as far as I can tell it's only _y that gets used internally by the interpolator, so I think you could get away without actually updating y at all. 事实上,据我所知,只有_y被内插器内部使用,所以我认为你可以在没有实际更新y情况下逃脱。

A much more elegant solution would be to make _y a property of the interpolator that returns a suitably reshaped copy of y . 一个更优雅的解决方案是使_y成为插值器的一个属性,它返回一个适当重新整形的y副本。 It's possible to achieve this by monkey-patching your specific instance of interp1d after it has been created (see Alex Martelli's answer here for more explanation): 这是可能的猴子修补您的具体实例来实现这一目标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)

Now itpr._y gets updated when you update itpr.y 现在itpr._y当你更新得到更新itpr.y

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

This is all quite fiddly and not very Pythonic - it's much easier to fix the scipy source code (scipy/interpolate/interpolate.py). 这一切都非常繁琐而且不是非常Pythonic - 修复scipy源代码(scipy / interpolate / interpolate.py)要容易得多。 All you'd need to do is remove the last line from interp1d.__init__() where it sets: 您需要做的就是从interp1d.__init__()中删除最后一行:

self._y = y

and add these lines: 并添加以下行:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM