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

Python 如何矢量化/优化依赖于先前行的计算,python,pandas,numpy,optimization,vectorization,Python,Pandas,Numpy,Optimization,Vectorization,我正在研究一些运行时非常重要并且我们正在处理的数据非常大的问题,但基本上问题归结为对已知x1和前一行x=ax+b的系列x的优化求解。例如,起始状态: a b x 1 2 3 3 1 2 2 4 8 1 9 最终状态如下所示: a b x 1 2 3 3 1 5 2 2 16 4 8 72 1 9 81 for i in range(2,len(df)): df.x[i] = df.x[i-1]*df.a[i-1]+df.b[i-1] 因为3*1+2=5,5*3+1=16,等等 我试

我正在研究一些运行时非常重要并且我们正在处理的数据非常大的问题,但基本上问题归结为对已知x1和前一行x=ax+b的系列x的优化求解。例如,起始状态:

a b x
1 2 3
3 1
2 2
4 8
1 9
最终状态如下所示:

a b x
1 2 3
3 1 5
2 2 16
4 8 72
1 9 81
for i in range(2,len(df)):
    df.x[i] = df.x[i-1]*df.a[i-1]+df.b[i-1]
因为3*1+2=5,5*3+1=16,等等

我试着算出它的数学结果是:

b0 = x1
xi = sum(n=0 to i-1)(bn*product(m=n+1 to i-1)(am)
x3 = a1*a2*b0 + b1*a2 + b2 = 3*1*3 + 2*3 + 1 = 9 + 6 + 1 = 16
例如,对于第三排,您将得到:

b0 = x1
xi = sum(n=0 to i-1)(bn*product(m=n+1 to i-1)(am)
x3 = a1*a2*b0 + b1*a2 + b2 = 3*1*3 + 2*3 + 1 = 9 + 6 + 1 = 16
但在计算上,这似乎比仅仅通过在行上循环来计算每个x更糟糕,比如:

a b x
1 2 3
3 1 5
2 2 16
4 8 72
1 9 81
for i in range(2,len(df)):
    df.x[i] = df.x[i-1]*df.a[i-1]+df.b[i-1]
有没有一种更简单的方法来解决我所缺少的问题,或者我只是在处理一个计算代价高昂的操作,我将不得不消耗迭代的成本?如果a条款不存在,bn部分可以通过cumsum解决,比如:

df['b_cumsum'] = x1+cumsum(df.b)
但当我试图包含a项时,我最终遇到了麻烦,特别是因为我们最终需要这么多不同的产品集,甚至在每个求和项中


谢谢。

当我遇到无法矢量化的函数时,但它需要高效,我使用
numba
。这是一个即时编译(JIT)模块。大多数情况下,这可能比本地方法更快:

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())


注意:当您想计时时。不要在第一次运行时计时,因为它还没有编译。首先运行一次,然后在第二次运行时计时。

当我运行函数时,我无法矢量化,但它需要高效,我使用
numba
。这是一个即时编译(JIT)模块。大多数情况下,这可能比本地方法更快:

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())


注意:当您想计时时。不要在第一次运行时计时,因为它还没有编译。首先运行一次,然后在第二次运行时计时。

您可以首先使用匹配的b'=b/cumprod(a)计算重新缩放的x:x'=x/cumprod(a)

这可以通过矢量化操作完成,也可以通过从x'到x的反向变换完成:


您可以首先使用匹配的b'=b/cumprod(a)计算重新缩放的x:x'=x/cumprod(a)

这可以通过矢量化操作完成,也可以通过从x'到x的反向变换完成:


我不认为它可以矢量化,因为这是一个滚动计算。所以,你可能要求我们打败这个循环代码,我不认为它可以矢量化,因为这是一个滚动计算。所以,你可能是在要求我们打破这个不合理的规则,这显然是可行的,看起来是一个非常优雅的解决方案,但是你介意解释一下数学吗?我知道这个比例只是cumprod(a),但是xp如何正确计算x/cumprod(a)?谢谢。@zachvac这样想:如果比例因子(a列)都是1,那就容易了。通过重新调整x的大小,我们可以精确地实现这一点。我们必须使用a的cumprod,因为原始缩放是累积的。一旦这一点明确了,我们只需观察到b必须以与x相同的方式进行缩放以保持一致性。对不起,我肯定达到了总体目标,也许我花了太多时间试图推导总和/乘积,以了解其工作原理。作为求解x5的示例,我得到:[a1-a4]*x1+b1*[a2-a4]+b2*[a3-a4]+b3*a4+b4,其中括号表示这些术语的乘积。当有2-4,3-4,然后是a4的乘积时,你怎么能用一个cumprod从1到4只缩放一次?哦,等等,我算出了它,我看到了它是如何工作的,它是分母中累积乘积的累积和,分子在第一项中抵消了所有分母,大部分在第二项中,我将进一步研究这个问题,但这非常有帮助,非常感谢。好吧,我的解释是:我们总是以cumprod(a)*x1+b1*[a2 an]+b2*[a3 an]+。。。bn-sox/cumprod(a)=x1+b1/a1+b2/a1-a2+…+bn/a1an所以我完全理解它为什么会起作用,我只是不太理解缩放的解释,或者如果没有一个非常幸运的猜测,怎么可能得到那个解决方案。我想意识到[ai an]/[a1 an]=1/(cumprod(a)at I)将是关键,看起来你是以一种更直观的方式到达那里的。这显然有效,看起来是一个非常优雅的解决方案,但你介意解释一下数学吗?我知道这个比例只是cumprod(a),但是xp如何正确计算x/cumprod(a)?谢谢。@zachvac这样想:如果比例因子(a列)都是1,那就容易了。通过重新调整x的大小,我们可以精确地实现这一点。我们必须使用a的cumprod,因为原始缩放是累积的。一旦这一点明确了,我们只需观察到b必须以与x相同的方式进行缩放以保持一致性。对不起,我肯定达到了总体目标,也许我花了太多时间试图推导总和/乘积,以了解其工作原理。作为求解x5的示例,我得到:[a1-a4]*x1+b1*[a2-a4]+b2*[a3-a4]+b3*a4+b4,其中括号表示这些术语的乘积。当有2-4,3-4,然后是a4的乘积时,你怎么能用一个cumprod从1到4只缩放一次?哦,等等,我算出了它,我看到了它是如何工作的,它是分母中累积乘积的累积和,分子在第一项中抵消了所有分母,大部分在第二项中,我将进一步研究这个问题,但这非常有帮助,非常感谢。好吧,我的解释是:我们总是以cumprod(a)*x1+b1*[a2 an]+b2*[a3 an]+。。。bn-sox/cumprod(a)=x1+b1/a1+b2/a1-a2+…+bn/a1an所以我完全理解它为什么会起作用,我只是不太理解缩放的解释,或者如果没有一个非常幸运的猜测,怎么可能得到那个解决方案。我想意识到[ai an]/[a1 an]=1/(cumprod(a)at I)将是关键,你似乎以更直观的方式到达了那里。