【问题标题】:Remove for loops to make it faster - numpy删除 for 循环以使其更快 - numpy
【发布时间】:2018-11-22 08:47:30
【问题描述】:

我有这个使用 numpy 的 python 代码:

import numpy as np
table = np.array([[23, 54, 12], 
                 [17, 32, 25],
                 [43, 19, 11],
                 [31, 22, 10],
                 [21, 19, 35]])
r, c = table.shape
out = np.zeros((r,c)) 
out[0, :] = np.cumsum(table[0,:])
out[:, 0] = np.cumsum(table[:,0]) 

for j in range(1, c):
    for i in range(1, r):
        out[i,j] = max( out[i-1,j], out[i,j-1] ) + table[i,j]

out[-1,-1]

我首先计算数组“out”的第一行和第一列,而其余的值是用 for 循环内的等式计算的。我只对表格的最后一个值( out[-1,-1] )感兴趣,我想尽可能快地完成它。我可以以某种方式删除两个“for”循环吗??

【问题讨论】:

  • 你尝试了什么?
  • 我尝试让它递归但没有成功,但我仍然认为它不会像那样快。我真的需要尽快完成
  • 欢迎来到 SO。请尝试从另一个用户的角度来思考,他们对您的问题一无所知,这可能在您的脑海中已经存在数天或数周。所以,minimal reproducible exampleHow to Ask 在这里申请。我想说您的代码甚至没有运行,因为您忘记了表定义中的外括号...

标签: python performance numpy


【解决方案1】:

这实际上是找到从每个坐标到 0,0 的最长路径,其中路径上每个节点的成本由表给出。处理此类问题的标准“矩阵方法”是 Floy-Warshall 算法,它进行 n 矩阵乘法,其中 n 是节点数,在您的情况下为 r*c。您的算法实际上已经是 Floyd-Warshall 的优化变体,它使用从 (i,j) 到 (0,0) 的每条路径必须通过 (i-1,j) 或 (i,j-1) 的事实.

这已经是一个巨大的优化了!

如果不对所有坐标进行迭代,我认为没有办法解决这个问题。

但也许您可以使用一些图形库将其编码为图形问题,这会将迭代部分推入(高效)图形库中。

甚至更好:

您可以迭代对角线,例如使用 fill_diagonal。这样,您将仅迭代对角线的数量。

【讨论】:

    【解决方案2】:

    我不完全确定你想要完成什么。

    您正在创建一个新的out 数组,该数组从原始表中复制第一(0)行和第一列。 (顺便说一下,out[:, 0] = np.cumsum(table[:,0]),你覆盖了[0, 0] 的元素)。

    然后,您继续填充 out 数组的其余部分,方法是取前一行中的元素或前一列中的元素的最大值。

    然后,您将在该位置添加原始数组 table 的内容到最大值。

    由于您要在 out 数组中查找以前的行和列,因此您经常会发现自己在检查这些值之前已经覆盖了它们。 例如,当你在 i=2, j=1 时,你已经得到了数组

    [[ 23.  77.  89.]
     [ 40. 109.   0.]
     [ 83.  *?*   0.]
     [114.   0.   0.]
     [135.   0.   0.]]
    

    您在 *?* 并检查 109 和 83。而您刚刚在上一次迭代中插入了 109。

    因此,如果不使用那些 for 循环,您将无法获得相同的结果。

    【讨论】:

    • 我只想要表格的最后一个值,而不是整个表格。我也没有更改 [0,0] 处的元素,虽然我覆盖了它,但它仍然具有相同的值,因为它是第一个元素的 cumsum
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-01
    • 2016-05-30
    • 1970-01-01
    • 2014-04-30
    • 1970-01-01
    • 2021-06-11
    • 2019-12-25
    相关资源
    最近更新 更多