简体   繁体   English

如何矢量化/优化依赖于先前行的计算

[英]How to vectorize/optimize calculations that rely on prior rows

I'm working on something where runtime is extremely important and the data we're working with is large, but basically the problem boils down to optimizing solving for series x where x1 is known and x = ax+b from the prior row.我正在研究运行时间非常重要并且我们正在处理的数据很大的问题,但基本上问题归结为优化求解系列 x ,其中 x1 已知且 x = ax+b 来自前一行。 So for example, starting state:例如,起始状态:

a b x
1 2 3
3 1
2 2
4 8
1 9

and the end state would look like this:最终状态将如下所示:

a b x
1 2 3
3 1 5
2 2 16
4 8 72
1 9 81

because 3*1+2 = 5, 5*3+1 = 16, etc.因为 3*1+2 = 5、5*3+1 = 16 等等。

I tried working out the math of it and I ended up with:我试着计算它的数学,我最终得到:

b0 = x1
xi = sum(n=0 to i-1)(bn*product(m=n+1 to i-1)(am)

So for example for the 3rd row you'd end up with:因此,例如对于第三行,您最终会得到:

x3 = a1*a2*b0 + b1*a2 + b2 = 3*1*3 + 2*3 + 1 = 9 + 6 + 1 = 16

But computationally that seems to be worse than just calculating each x by looping over rows, something like this:但在计算上,这似乎比通过遍历行来计算每个 x 更糟糕,如下所示:

for i in range(2,len(df)):
    df.x[i] = df.x[i-1]*df.a[i-1]+df.b[i-1]

Is there an easier way to tackle this that I'm missing, or am I just dealing with a computationally expensive operation that I'll have to eat the cost of iterating?有没有更简单的方法来解决我遗漏的这个问题,或者我只是在处理一个计算成本高的操作,我将不得不承担迭代的成本? If the a term didn't exist the bn portion could be tackled via cumsum, something like:如果 a 术语不存在,则可以通过 cumsum 处理 bn 部分,例如:

df['b_cumsum'] = x1+cumsum(df.b)

but I end up hitting a wall when trying to include the a terms, especially since we end up needing so many different sets of products even within each sum term.但是当我试图包含 a 项时,我最终碰壁了,特别是因为我们最终需要这么多不同的产品集,即使在每个总和项中也是如此。

Thanks.谢谢。

When I run into functions I cannot vectorize, but it needs to be efficient, I use numba .当我遇到无法矢量化但需要高效的函数时,我使用numba Which is a just in time compilation (JIT) module.这是一个即时编译 (JIT) 模块。 Most of the times this can be even faster than the native pandas methods:大多数情况下,这甚至比原生的 Pandas 方法还要快:

from numba import njit

@njit
def calculation(arr):
    result = np.empty(arr.shape[0])
    for idx, row in enumerate(arr):
        if idx == 0:
            result[idx] = row[2]
        else:
            row = arr[idx-1]
            result[idx] = result[idx-1] * row[0] + row[1]
    
    return result

df['x'] = calculation(df.to_numpy())
print(df)

   a  b      x
0  1  2    3.0
1  3  1    5.0
2  2  2   16.0
3  4  8   34.0
4  1  9  144.0

note : when you want to time it.注意:当你想计时。 Don't time it on the first run, since it did not compile yet.不要在第一次运行时计时,因为它还没有编译。 First run it once, then time it on the second run.首先运行一次,然后在第二次运行时计时。

You can first calculate a rescaled x : x ' = x /cumprod( a ) using a matching b ' = b /cumprod( a )您可以首先计算重新缩放的xx ' = x /cumprod( a ) 使用匹配的b ' = b /cumprod( a )

This can be done with vectorized operations as can the backtransform from x ' to x :这可以通过向量化操作来完成,就像从x ' 到x的反向变换一样:

ab = np.array([[1, 2],
               [3, 1],
               [2, 2],
               [4, 8],
               [1, 9]])

scale = ab.T[0].cumprod()
xp = 3+(ab.T[1]/scale).cumsum()
x = xp*scale
x
array([  5.,  16.,  34., 144., 153.])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM