如何将此循环向量化?

时间:2018-08-24 06:11:24

标签: python numpy

我有一个类似的numpy数组:

array([[ -1. , 184. ,   0.5],
       [ -1. , 174. ,   1.0],
       [ -1. , 104. ,   0.5],
       [  1. ,  44. ,   0.5],
       [  1. ,  28. ,   0.5],
       [  1. ,  70. ,   0.5],
       [ -1. ,  34. ,   0.5],
       ...,
       [  1. ,  10. ,   0.5],
       [  1. ,  12. ,   0.5],
       [  1. ,  86. ,   1.0],
       [ -1. ,  36. ,   0.5],
       [  1. ,   2. ,   0.5],
       [ -1. ,  32. ,   1.5],
       [  1. ,  10. ,   0.5]])

我有一个函数来查找满足for循环中列出的条件的数组索引:

def loop(array):
    n_init = 100
    a = np.dot(array[:n_init, 0], array[:n_init, 1])
    b = np.sum(array[:n_init, 2])
    loc_start = n_init
    idx = []
    lst_a, lst_b = [], []
    lst_a.append(a)
    lst_b.append(b)
    for step in range(n_init + 1, array.shape[0]):
        mean_a = np.mean(lst_a)
        mean_b = np.mean(lst_b)
        _a = np.dot(array[loc_start:step, 0], array[loc_start:step, 1])
        _b = np.sum(array[loc_start:step, 2])
        if np.abs(_a) * _b >= np.abs(mean_a) * mean_b:
            loc_start = step
            lst_a.append(_a)
            lst_b.append(_b)
            idx.append(step)
    return idx

该函数首先初始化n_init行,以计算2个标量a和b,这些标量被附加到稍后在for循环中使用的列表lst_a和lst_b中。

在循环中,从n_init行之后的条目开始,分别显示lst_a和lst_b的平均值,以及_a(从最后一个idx到当前步骤的列0和1的点运算)和_b(从最后一个idx到当前步骤的第2列)。

当_a的绝对值乘以_b的绝对值大于或等于lst_a的均值的绝对值乘以lst_b的均值时,会找到行号,即附加到idx的索引,并作为条件如果满足,则将当前_a和_b分别附加到lst_a和lst_b。当step到达数组的长度时,整个循环结束。

由于该数组具有数百万行,因此需要很长时间才能完成。可以对这个过程进行向量化吗?

2 个答案:

答案 0 :(得分:0)

好吧,您正在建立一个状态(lst_alst_b),并使用它来检查新条目是否应属于该状态。因此,我认为它不能完全矢量化。

您可以尝试加快速度的方法是使用增量计算(实际上是矢量化的逆过程,如果可以的话)。

例如mean_amean_b当前在每个步骤都被重新计算,即使它没有改变,并且当它改变时,您可以对其进行更新而不是完全重新计算。

还可以更新_a_b而不是重新计算。这样可以节省数组切片和少量计算(如果loc_start距离不太远,可能不值得)。 试试看并进行比较。

答案 1 :(得分:0)

您无法对其进行矢量化处理(因为您要迭代填充列表并在计算中使用它们),但是您可以预先进行很多矢量化的计算。也许。

def loop(array):
    loc_start = 100
    A = np.cumsum(array[:, 0] * array[:, 1])
    B = np.cumsum(array[:, 2])
    a, b = A[loc_start], B[loc_start]
    idx = []
    lst_a, lst_b = [a], [b]
    thr = np.abs(a)/ b
    for step in range(n_init + 1, array.shape[0]):
        _a = A[step] - a
        _b = B[step] - b
        if np.abs(_a) * _b >= thr:
            loc_start = step
            a, b = a_, b_
            lst_a.append(a)
            lst_b.append(b)
            thr = np.abs(np.mean(lst_a)) / np.mean(lst_b)
            idx.append(step)
    return idx

只要您的cumsum数组不会溢出(请检查A[-1]B[-1]的值),这应该会更快。