如果我想要使用空插值(分段常数)的最佳替代方法取代numpy.interp,应该选择什么?

6

numpy.interp非常方便且相对快速。在某些情况下,我想将其输出与未插值的变体进行比较,在该变体中,稀疏值会被传播(在“密集”输出中),并且结果在稀疏输入之间为分段常数。我想要的函数也可以称为“稀疏->密集”转换器,它复制最新的稀疏值,直到它找到更晚的值(一种空插值,就好像从早期值起从未经过零时间/距离)。

不幸的是,调整numpy.interp源代码并不容易,因为它只是编译函数的包装器。我可以使用Python循环自己编写此功能,但希望找到一种C速度的方法来解决问题。

更新:下面的解决方案(使用kind ='zero'scipy.interpolate.interp1d )非常慢,并且每次调用需要超过10秒钟(例如500k长度的输入,其中50%填充)。它使用零阶样条实现kind =' zero ',并且对spleval的调用非常缓慢。然而,kind ='linear'(即默认插值)的源代码为使用纯numpy解决问题提供了极好的模板(最小更改是将slope = 0 )。该代码展示了如何使用numpy.searchsorted来解决问题,运行时间类似于调用numpy.interp ,因此通过调整scipy.interpolate.interp1d 实现线性插值即可跳过插值步骤(斜率!= 0混合相邻值)。


只是想说谢谢你的更新 - 我想在numpy中进行零插值,而不需要完全依赖于scipy,而你的帖子更新指明了实现方法。在我进行的小型测试中,numpy 1.5.1:安装了0.8.0的scipy_fitpack.so,测试时间为308到508微秒;而仅使用slope=0numpy线性插值需要491到778微秒 - 所以对我来说它更慢了一些;但并不是太多!再次感谢 - 干杯! - sdaau
3个回答

4

1
很遗憾,每次更新问题的速度都非常慢。这是一个完全有效的答案,但底层的样条实现不太高效。 - Joseph Hastings

2

仅供参考:问题的解决方案是以下代码,我在更新的答案中得到了提示并成功编写出来:

def interpolate_constant(x, xp, yp):
    indices = np.searchsorted(xp, x, side='right')
    y = np.concatenate(([0], yp))
    return y[indices]

0

我完全同意kind='zero'的速度非常慢;对于一个包含百万行数据的大型数据集,它可能比'linear'方法慢上1000倍。对于“左常数”插值-使用最新的值-下面的代码可以实现:

def approx(x, y, xout, yleft=np.nan, yright=np.nan): 
    xoutIdx     = np.searchsorted(x, xout, side='right')-1
    return (np.where(xout<x[0], yleft, np.where(xout>x[-1], yright, y[xoutIdx])))

如果你来自R语言的背景,这个函数相当于R中的approx函数,其中f=0。但是我还没有找到一种干净的方法来实现“右常数”插值,因为Python中的np.searchsorted函数使用side='right'参数时,如果xout的值与x中的某个值完全匹配,它会将一个索引向后推。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接