是否有一种使用零阶保持重新采样numpy数组的有效方法?理想情况下具有类似numpy.interp的签名的东西?
我知道scipy.interpolate.interp1d,但我确信有一个矢量化的替代品可用于处理这样的案例。
答案 0 :(得分:5)
由于您不会插入任何新值,您不能只保留原始数组并通过一些用户定义的包装器访问索引它吗?您可以利用numpy数组的非整数索引。
要查看我的意思,请使用x = np.array(range(10))
,例如(x[i] for i in np.linspace(0, len(x)-1, num=25))
类似于零阶保持。
答案 1 :(得分:1)
Numpy数组不再允许非整数索引,因此接受的解决方案不再有效。 scipy.interpolate.interp1d很强大,但在许多情况下不是最快的。这是一个健壮的代码解决方案,它在可能的情况下使用np.searchsorted,在无法使用的情况下恢复为scipy版本。
import numpy as np
from scipy.interpolate import interp1d
def zero_order_hold(x, xp, yp, left=np.nan, assume_sorted=False):
r"""
Interpolates a function by holding at the most recent value.
Parameters
----------
x : array_like
The x-coordinates at which to evaluate the interpolated values.
xp: 1-D sequence of floats
The x-coordinates of the data points, must be increasing if argument period is not specified. Otherwise, xp is internally sorted after normalizing the periodic boundaries with xp = xp % period.
yp: 1-D sequence of float or complex
The y-coordinates of the data points, same length as xp.
left: int or float, optional, default is np.nan
Value to use for any value less that all points in xp
assume_sorted : bool, optional, default is False
Whether you can assume the data is sorted and do simpler (i.e. faster) calculations
Returns
-------
y : float or complex (corresponding to fp) or ndarray
The interpolated values, same shape as x.
Notes
-----
#. Written by DStauffman in July 2020.
Examples
--------
>>> import numpy as np
>>> xp = np.array([0., 111., 2000., 5000.])
>>> yp = np.array([0, 1, -2, 3])
>>> x = np.arange(0, 6001, dtype=float)
>>> y = zero_order_hold(x, xp, yp)
"""
# force arrays
x = np.asanyarray(x)
xp = np.asanyarray(xp)
yp = np.asanyarray(yp)
# find the minimum value, as anything left of this is considered extrapolated
xmin = xp[0] if assume_sorted else np.min(xp)
# check that xp data is sorted, if not, use slower scipy version
if assume_sorted or np.all(xp[:-1] <= xp[1:]):
ix = np.searchsorted(xp, x, side='right') - 1
return np.where(np.asanyarray(x) < xmin, left, yp[ix])
func = interp1d(xp, yp, kind='zero', fill_value='extrapolate', assume_sorted=False)
return np.where(np.asanyarray(x) < xmin, left, func(x))
这通过了一系列测试用例:
import unittest
import numpy as np
from scipy.interpolate import interp1d
class Test_zero_order_hold(unittest.TestCase):
r"""
Tests the zero_order_hold function with the following cases:
Subsample high rate
Supersample low rate
xp Not sorted
x not sorted
Left extrapolation
Lists instead of arrays
Notes
-----
#. Uses scipy.interpolate.interp1d as the gold standard (but it's slower)
"""
def test_subsample(self):
xp = np.linspace(0., 100*np.pi, 500000)
yp = np.sin(2 * np.pi * xp)
x = np.arange(0., 350., 0.1)
func = interp1d(xp, yp, kind='zero', fill_value='extrapolate', assume_sorted=True)
y_exp = func(x)
y = zero_order_hold(x, xp, yp)
np.testing.assert_array_equal(y, y_exp)
y = zero_order_hold(x, xp, yp, assume_sorted=True)
np.testing.assert_array_equal(y, y_exp)
def test_supersample(self):
xp = np.array([0., 5000., 10000., 86400.])
yp = np.array([0, 1, -2, 0])
x = np.arange(0., 86400.,)
func = interp1d(xp, yp, kind='zero', fill_value='extrapolate', assume_sorted=True)
y_exp = func(x)
y = zero_order_hold(x, xp, yp)
np.testing.assert_array_equal(y, y_exp)
y = zero_order_hold(x, xp, yp, assume_sorted=True)
np.testing.assert_array_equal(y, y_exp)
def test_xp_not_sorted(self):
xp = np.array([0, 10, 5, 15])
yp = np.array([0, 1, -2, 3])
x = np.array([10, 2, 14, 6, 8, 10, 4, 14, 0, 16])
y_exp = np.array([ 1, 0, 1, -2, -2, 1, 0, 1, 0, 3])
y = zero_order_hold(x, xp, yp)
np.testing.assert_array_equal(y, y_exp)
def test_x_not_sorted(self):
xp = np.array([0, 5, 10, 15])
yp = np.array([0, -2, 1, 3])
x = np.array([10, 2, 14, 6, 8, 10, 4, 14, 0, 16])
y_exp = np.array([ 1, 0, 1, -2, -2, 1, 0, 1, 0, 3])
y = zero_order_hold(x, xp, yp)
np.testing.assert_array_equal(y, y_exp)
def test_left_end(self):
xp = np.array([0, 5, 10, 15, 4])
yp = np.array([0, 1, -2, 3, 0])
x = np.array([-4, -2, 0, 2, 4, 6])
y_exp = np.array([-5, -5, 0, 0, 0, 1])
y = zero_order_hold(x, xp, yp, left=-5)
np.testing.assert_array_equal(y, y_exp)
def test_lists(self):
xp = [0, 5, 10, 15]
yp = [0, 1, 2, 3]
x = [-4, -2, 0, 2, 4, 6, 20]
y_exp = [-1, -1, 0, 0, 0, 1, 3]
y = zero_order_hold(x, xp, yp, left=-1)
np.testing.assert_array_equal(y, y_exp)
前两个测试的速度测试表明,对于高速率数据进行二次采样,numpy解决方案的速度提高了约100倍,对低速率数据进行超采样的速度提高了约3倍。
答案 2 :(得分:0)
派对有点晚了,但这就是我想出的:
from numpy import zeros, array, sign
def signal_zoh(x,y,epsilon = 0.001):
"""
Fills in the data from a Zero-Order Hold (stair-step) signal
"""
deltaX = array(x[1:],dtype='float') - x[:-1]
fudge = min(deltaX) *epsilon
retX = zeros((len(x)*2-1,))
retY = zeros((len(y)*2-1,))
retX[0::2] = x
retX[1::2] = x[1:]+fudge*sign(deltaX)
retY[0::2] = y
retY[1::2] = y[:-1]
return retX,retY
答案 3 :(得分:0)
这是一个numpy免费版本,具有相同的签名。数据需要按顺序递增 - b / c它们会在您通过“聪明”使用列表作为嵌套函数默认值(100倍加速)时被抛弃:
def interp0(x, xp, yp):
"""Zeroth order hold interpolation w/ same
(base) signature as numpy.interp."""
from collections import deque
def func(x0, xP=deque(xp), yP=deque(yp)):
if x0 <= xP[0]:
return yP[0]
if x0 >= xP[-1]:
return yP[-1]
while x0 > xP[0]:
xP.popleft() # get rid of default
y = yP.popleft() # data as we go.
return y
return map(func, x)