需要帮助加快 numpy 代码的速度,以查找两个 NumPy 数组之间的“重合”数量

Son*_*era 5 python numpy vectorization

我正在寻求一些帮助来加速我用 Numpy 编写的一些代码。这是代码:

def TimeChunks(timevalues, num):
    avg = len(timevalues) / float(num)
    out = []
    last = 0.0

    while last < len(timevalues):
        out.append(timevalues[int(last):int(last + avg)])
        last += avg

    return out
### chunk i can be called by out[i] ###

NumChunks = 100000
t1chunks = TimeChunks(t1, NumChunks)
t2chunks = TimeChunks(t2, NumChunks)

NumofBins = 2000

CoincAllChunks = 0
for i in range(NumChunks):
    CoincOneChunk = 0
    Hist1, something1 = np.histogram(t1chunks[i], NumofBins)
    Hist2, something2 = np.histogram(t2chunks[i], NumofBins)

    Mask1 = (Hist1>0)
    Mask2 = (Hist2>0)
    MaskCoinc = Mask1*Mask2
    CoincOneChunk = np.sum(MaskCoinc)
    CoincAllChunks = CoincAllChunks + CoincOneChunk  
Run Code Online (Sandbox Code Playgroud)

是否可以采取任何措施来改进这一点,使其对于大型数组更有效?

简而言之,代码的目的只是找到两个 NumPy 数组之间的平均“重合”,表示两个通道的时间值(除以某个归一化常数)。当在某一时间间隔内两个通道中的每一个通道中至少存在一个时间值时,就会出现这种“重合”。

例如:

t1 = [.4, .7, 1.1]
t2 = [0.8, .9, 1.5]
Run Code Online (Sandbox Code Playgroud)

在窗口 [0,1] 内有一个重合,在区间 [1, 2] 内有一个重合。

当我将时间数组分解为多个均匀分布的容器时,我想找到这些“巧合”的平均数量。例如,如果:

t1 = [.4, .7, 1.1, 2.1, 3, 3.3]
t2 = [0.8, .9, 1.5, 2.2, 3.1, 4]
Run Code Online (Sandbox Code Playgroud)

我想要 4 个 bin,我要考虑的间隔是 ([0,1], [1,2], [2,3], [3,4])。因此,总重合数将为 4(因为每个 bin 中都有一个重合数),因此平均重合数将为 4。

该代码尝试对非常小的 bin 大小的大型时间数组执行此操作,因此,为了使其工作,我必须将时间数组分解为较小的块,然后对每个块进行 for 循环。

我已经尝试使其尽可能矢量化,但它仍然非常慢......有什么想法可以做些什么来进一步加快速度吗?

任何建议/提示将不胜感激。谢谢!。

Abo*_*mar 3

使用比numba_histogram通用np.histogram. 请注意,您正在分别计算和比较两个不同系列的直方图,这对于您的目的来说并不准确。因此,在我的numba_histogram函数中,我使用相同的 bin 边缘来同时计算两个系列的直方图。

如果您提供有关算法的更精确的详细信息,我们仍然可以进一步优化它。也就是说,如果您提供有关参数的具体详细信息以及您确定两个间隔一致的标准。

import numpy as np
from numba import njit

@njit
def numba_histogram(a, b, n):
    hista, histb = np.zeros(n, dtype=np.intp), np.zeros(n, dtype=np.intp)
    a_min, a_max = min(a[0], b[0]), max(a[-1], b[-1])
    for x, y in zip(a, b):
        bin = n * (x - a_min) / (a_max - a_min)
        if x == a_max:
            hista[n - 1] += 1
        elif bin >= 0 and bin < n:
            hista[int(bin)] += 1        
        bin = n * (y - a_min) / (a_max - a_min)
        if y == a_max:
            histb[n - 1] += 1
        elif bin >= 0 and bin < n:
            histb[int(bin)] += 1
    return np.sum( (hista > 0) * (histb > 0) )

@njit 
def calc_coincidence(t1, t2):
    NumofBins = 2000
    NumChunks = 100000
    avg = len(t1) / NumChunks
    CoincAllChunks = 0
    last = 0.0
    while last < len(t1):
        t1chunks = t1[int(last):int(last + avg)]
        t2chunks = t2[int(last):int(last + avg)]
        CoincAllChunks += numba_histogram(t1chunks, t2chunks, NumofBins)
        last += avg 
    return CoincAllChunks
Run Code Online (Sandbox Code Playgroud)

使用10**8数组进行测试:

t1 = np.arange(10**8) + np.random.rand(10**8)
t2 = np.arange(10**8) + np.random.rand(10**8)
CoincAllChunks = calc_coincidence(t1, t2)
print( CoincAllChunks )
 # 34793890    Time: 24.96140170097351 sec.  (Original)
 # 34734897    Time: 1.499996423721313 sec.  (Optimized)
Run Code Online (Sandbox Code Playgroud)