Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/360.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何将此python代码矢量化?_Python_Numpy_Vectorization - Fatal编程技术网

如何将此python代码矢量化?

如何将此python代码矢量化?,python,numpy,vectorization,Python,Numpy,Vectorization,我正在尝试使用NumPy和矢量化操作来加快代码的运行速度。然而,我似乎对如何向量化这段代码有误解(可能是因为对向量化的理解不完整) 下面是循环的工作代码(A和B是设置大小的2D数组,已经初始化): 下面是我对上述代码进行矢量化的尝试: for k in range(num_v): B = numpy.copy(A) A = numpy.minimum(B, B[:,k] + B[k,:]) return A 为了测试这些,我使用了以下代码,将上面的代码包装在一个名为“algor

我正在尝试使用NumPy和矢量化操作来加快代码的运行速度。然而,我似乎对如何向量化这段代码有误解(可能是因为对向量化的理解不完整)

下面是循环的工作代码(A和B是设置大小的2D数组,已经初始化):

下面是我对上述代码进行矢量化的尝试:

for k in range(num_v):
    B = numpy.copy(A)
    A = numpy.minimum(B, B[:,k] + B[k,:])
return A
为了测试这些,我使用了以下代码,将上面的代码包装在一个名为“algorithm”的函数中:

def setup_array(edges, num_v):
    r = range(1, num_v + 1)
    A = [[None for x in r] for y in r]  # or (numpy.ones((num_v, num_v)) * 1e10) for numpy
    for i in r:
        for j in r:
            val = 1e10
            if i == j:
                val = 0 
            elif (i,j) in edges:
                val = edges[(i,j)]
            A[i-1][j-1] = val 
    return A

A = setup_array({(1, 2): 2, (6, 4): 1, (3, 2): -3, (1, 3): 5, (3, 6): 5, (4, 5): 2, (3, 1): 4, (4, 3): 8, (3, 4): 6, (2, 4): -4, (6, 5): -5}, 6) 
B = []
algorithm(A, B, 6)
预期的结果,以及我从第一个代码中得到的结果是:

[[0, 2, 5, -2, 0, 10] 
 [8, 0, 4, -4, -2, 9]
 [4, -3, 0, -7, -5, 5]
 [12, 5, 8, 0, 2, 13]
 [10000000000.0, 9999999997.0, 10000000000.0, 9999999993.0, 0, 10000000000.0]
 [13, 6, 9, 1, -5, 0]]
第二个(矢量化)函数返回:

[[ 0. -4.  0.  0.  0.  0.]
 [ 0. -4.  0. -4.  0.  0.]
 [ 0. -4.  0.  0.  0.  0.]
 [ 0. -4.  0.  0.  0.  0.]
 [ 0. -4.  0.  0.  0.  0.]
 [ 0. -4.  0.  0. -5.  0.]]

我遗漏了什么?

通常您希望对代码进行矢量化,因为您认为它运行得太慢。
如果您的代码太慢,那么我可以告诉您,适当的索引将使其更快。
您应该编写
A[i,j]
,而不是
A[i,j]
——这样可以避免(子)数组的临时副本。
由于这是在代码的最内部循环中进行的,因此成本可能非常高

看这里:

In [37]: timeit test[2][2]
1000000 loops, best of 3: 1.5 us per loop

In [38]: timeit test[2,2]
1000000 loops, best of 3: 639 ns per loop
在代码中始终如一地做到这一点——我坚信这已经解决了性能问题

话虽如此

... 以下是我对如何矢量化的看法 将比较两个数组并返回两个元素中较小的元素。如果传递第三个参数,它将接受输出。如果这是一个输入数组,则整个操作都已就绪

正如Peter de Rivay所解释的,广播解决方案中存在一个问题——但从数学上讲,你想要做的是两个向量相加的某种外积。因此,您可以在add函数上使用outer操作

NumPy的二进制UFUNC用于执行某些类型的
特殊的矢量化操作,如reduce、congregate、sum和outer。

该问题是由线路中的阵列广播引起的:

A = numpy.minimum(B, B[:,k] + B[k,:])
B的大小是6乘6,B[:,k]是一个包含6个元素的数组,B[k,:]是一个包含6个元素的数组

(因为您使用的是numpy数组类型,所以B[:,k]和B[k,:]都返回形状为N的秩1数组)

Numpy会自动更改大小以匹配:

  • 将第一个B[:,k]添加到B[k,:]以生成包含6个元素的中间数组结果。(这不是你想要的)
  • 其次,通过重复行,将此6元素数组广播到6×6矩阵
  • 第三,计算原始矩阵和该广播矩阵的最小值
  • 这意味着您的numpy代码相当于:

    for k in range(num_v):
       B[:] = A[:]
       C=[B[i][k]+B[k][i] for i in range(num_v)]
       for i in range(num_v):
          for j in range(num_v):
             A[i][j] = min(B[i][j], C[j])
    
    修复代码的最简单方法是使用矩阵类型而不是数组类型:

    A = numpy.matrix(A)
    for k in range(num_v):
        A = numpy.minimum(A, A[:,k] + A[k,:])
    
    矩阵类型使用更严格的广播规则,因此在这种情况下:

  • A[:,k]通过重复列扩展为6×6矩阵
  • [k,:]通过重复行扩展为6×6矩阵
  • 广播矩阵相加,形成6×6矩阵
  • 应用最小值

  • 很好的解释,谢谢!我不敢相信我的代码现在快了多少!仅此一项更改就将整个代码(在不同数据上)的运行时间从45分钟减少到不到一秒钟。
    for k in range(num_v):
       B[:] = A[:]
       C=[B[i][k]+B[k][i] for i in range(num_v)]
       for i in range(num_v):
          for j in range(num_v):
             A[i][j] = min(B[i][j], C[j])
    
    A = numpy.matrix(A)
    for k in range(num_v):
        A = numpy.minimum(A, A[:,k] + A[k,:])