快速 numpy 滚动_产品

Jas*_*rgh 4 python numpy python-2.7 pandas

我需要一个rolling_product 函数,或者一个expanding_product 函数。

有各种pandas rolling_XXXXexpanding_XXXX功能,但我很惊讶地发现缺少的expanding_product()功能。

为了让事情顺利进行,我一直在使用这种相当缓慢的替代方案

pd.expanding_apply(temp_col, lambda x : x.prod())
Run Code Online (Sandbox Code Playgroud)

我的数组通常有 32,000 个元素,所以这被证明是一个瓶颈。我很想尝试log(), cumsum(), 和exp(),但我想我应该在这里问一下,因为可能有更好的解决方案。

chr*_*ock 5

我有一个更快的机制,但您需要运行一些测试来查看准确性是否足够。

这是原始的 exp/sum/log 版本:

def rolling_prod1(xs, n):
    return np.exp(pd.rolling_sum(np.log(xs), n))
Run Code Online (Sandbox Code Playgroud)

这是一个版本,它采用累积乘积,将其转移(用 nans 预填充),然后将其划分回来。

def rolling_prod2(xs, n):
    cxs = np.cumprod(xs)
    nans = np.empty(n)
    nans[:] = np.nan
    nans[n-1] = 1.
    a = np.concatenate((nans, cxs[:len(cxs)-n]))
    return cxs / a
Run Code Online (Sandbox Code Playgroud)

对于此示例,两个函数都返回相同的结果:

In [9]: xs
Out[9]: array([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.])

In [10]: rolling_prod1(xs, 3)
Out[10]: array([  nan,   nan,    6.,   24.,   60.,  120.,  210.,  336.,  504.])

In [11]: rolling_prod2(xs, 3)
Out[11]: array([  nan,   nan,    6.,   24.,   60.,  120.,  210.,  336.,  504.])
Run Code Online (Sandbox Code Playgroud)

但是第二个版本要快得多:

In [12]: temp_col = np.random.rand(30000)

In [13]: %timeit rolling_prod1(temp_col, 3)
1000 loops, best of 3: 694 µs per loop

In [14]: %timeit rolling_prod2(temp_col, 3)
10000 loops, best of 3: 162 µs per loop
Run Code Online (Sandbox Code Playgroud)