scipy中重采样数组的索引

时间:2013-01-30 22:47:21

标签: python numpy python-3.x scipy

我有两个相同长度的1D阵列,包含时间序列和值系列,例如

t = linspace(0, 5, 5) # [0, 1.25, 2.5, 3.75, 5]
x = array(range(10, 25)) # [10, 11, 12, 13, 14]

我必须使用不同的采样点及时重新采样x数组(具有相同的起点和终点,但可以包含任意数量的元素),例如

r = linspace(0, 5, 4) # [ 0, 1.667, 3.333, 5]
x2 = resample(t, x, r) # [10, 11, 12, 14]

也就是说,r的每个时间点都放在t的两个时间点之间,我想在t中找到两个较低点的索引。从索引数组中,可以获得x的相对点。

我想要一个基于矢量的解决方案,没有循环,可能使用scipy的运算符。 如果使用scipy的函数会更好。

编辑:这是一个能够满足我需要的代码,但更短,更快,基于矢量的解决方案会更好。我找不到一个(直到尝试)。

def resample(t, r):
    i, j, k = 0, 1, 0
    s = []
    while j < len(t):
        if t[i] <= r[k] < t[j]:
            s.append(i)
            k += 1
        else:
            i += 1
            j += 1
    s.append(len(t) - 1)
    return array(s)

3 个答案:

答案 0 :(得分:1)

您可以尝试使用interp1d中的scipy.interpolate功能,将kind参数指定为zero。使用你的数组:

>>> from scipy.interpolate import interp1d
>>> f = interp1d(t,x,kind="zero")
>>> f(r)
array((10, 11, 12, 13))

请注意,“resampled”数组中的最后一个元素是13,而不是您在问题中请求的14,而是f(5.001) = 14(*)。只要“重采样”数组与原始数组中的一个点匹配,插值函数就是不连续的。

(*)如果要在bounds_error=False范围之外重新取样,则需要在interp1d调用中指定关键字参数t

答案 1 :(得分:1)

以下两个小函数中的第二个可以得到你想要的东西:

def resample_up(t, x, r) :
    return x[np.argmax(r[:, None] <= t, axis=1)]

def resample_down(t, x, r) :
    return x[::-1][np.argmax(r[:, None] >= t[::-1], axis=1)]

>>> resample_up(t, x, r)
array([10, 12, 13, 14])
>>> resample_down(t, x, r)
array([10, 11, 12, 14])

如果您发现很难弄清楚发生了什么,以下内容可能有所帮助:

>>> r[:, None] <= t
array([[ True,  True,  True,  True,  True],
       [False, False,  True,  True,  True],
       [False, False, False,  True,  True],
       [False, False, False, False,  True]], dtype=bool)
>>> r[:, None] >= t[::-1]
array([[False, False, False, False,  True],
       [False, False, False,  True,  True],
       [False, False,  True,  True,  True],
       [ True,  True,  True,  True,  True]], dtype=bool)

然后np.argmax返回每行中第一次出现True的索引。

编辑 IT很难让它比单行代码更短,但对于大型数组,性能会受到影响,因为索引查找从未在循环的早期发生。因此对于非常大的数组,使用python循环扫描数组可能会更快。对于较小的那些,它不会:

In [2]: %timeit resample_up(t, x, r)
100000 loops, best of 3: 7.32 us per loop

In [3]: %timeit resample_down(t, x, r)
100000 loops, best of 3: 8.44 us per loop

In [4]: %timeit resample(t, x, r) # modified version of the OP's taking also x
100000 loops, best of 3: 13.7 us per loop

答案 2 :(得分:1)

numpy.interp是一个快速简单的分段线性插值器:

from __future__ import division
import numpy as np

t = np.linspace(0, 5, 5)  # [0, 1.25, 2.5, 3.75, 5]
x = np.array(range(10, 15))  # [10, 11, 12, 13, 14]
r = np.linspace(0, 5, 4)  # [ 0, 1.667, 3.333, 5]

print "np.interp:", np.interp( r, t, x )
    # [ 10.    11.33  12.67  14.  ]
xint = np.arange( len(t) )
print "r to int:", np.interp( r, t, xint ).astype(int)
    # [0 1 2 4]