在 numpy 中计算累积乘积或总和时提前中断

Breaking early when computing cumulative products or sums in numpy

假设我有一个范围 r=numpy.array(range(1, 6)),我正在使用 numpy.cumsum(r) 计算累计和。但是我不想 returning [1, 3, 6, 10, 15] return [1, 3, 6] 因为条件是累积结果必须小于 10.

如果数组非常大,我希望在开始计算多余的值之前将累加和分解,这些值稍后会被丢弃。当然,为了这个问题,我把这里的一切都轻描淡写了。

是否可以根据条件提前突破cumsumcumprod

我认为这对 numpy 中的任何函数都是不可能的,因为在大多数情况下,这些函数用于固定长度数组的矢量化计算。做你想做的事情的一种明显方法是在 Python 中跳出标准 for 循环(我假设你知道):

def limited_cumsum(x, limit):
    y = []
    sm = 0
    for item in x:
        sm += item
        if sm > limit:
            return y
        y.append(sm)
    return y

但这显然比 numpy 的 cumsum 慢了一个数量级。

由于您可能需要一些非常专业的函数,因此更改很少以在 numpy 中找到您需要的确切函数。您可能应该看看 Cython,它允许您实现与 Python 函数一样灵活的自定义函数(并使用几乎 Python 的语法),并且速度接近C.

根据您要为其计算累计和的数组的大小以及您预计达到目标值的速度,逐步计算累计和可能会更快。

import numpy as np

size = 1000000
target = size
def stepped_cumsum():
    arr = np.arange(size)
    out = np.empty(len(arr), dtype=int) 
    step = 1000
    last_value = 0
    for i in range(0, len(arr), step):
        np.cumsum(arr[i:i+step], out=out[i:i+step])
        out[i:i+step] += last_value
        last_value = out[i+step-1]
        if last_value >= target:
            break
    else:
        return out
    greater_than_target_index = i + (out[i:i+step] >= target).argmax()
    # .copy() required so rest of backing array can be freed
    return out[:greater_than_target_index].copy()

def normal_cumsum():
    arr = np.arange(size)
    out = np.cumsum(arr)
    return out

stepped_result = stepped_cumsum()
normal_result = normal_cumsum()
assert (stepped_result < target).all()
assert (stepped_result == normal_result[:len(stepped_result)]).all()

结果:

In [60]: %timeit cumsum.stepped_cumsum()
1000 loops, best of 3: 1.22 ms per loop

In [61]: %timeit cumsum.normal_cumsum()
100 loops, best of 3: 3.69 ms per loop