如何向量化这个Python代码?(How to vectorize this python code

2019-07-18 12:00发布

我试图使用与NumPy和矢量化操作使代码运行的部分快。 我似乎有不过如何向量化这个代码,(可能是由于量化的不完全理解)一种误解。

下面是与环(A和B是一组尺寸的二维阵列,已经初始化)工作的代码:

for k in range(num_v):
    B[:] = A[:]
    for i in range(num_v):
        for j in range(num_v):
            A[i][j] = min(B[i][j], B[i][k] + B[k][j])
return A

这里是我的矢量化在上面的代码尝试:

for k in range(num_v):
    B = numpy.copy(A)
    A = numpy.minimum(B, B[:,k] + B[k,:])
return A

为了测试这些,我用下文中,上述包裹在称为“算法”功能的代码:

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.]]

我在想什么?

Answer 1:

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

A = numpy.minimum(B, B[:,k] + B[k,:])

B是尺寸为6×6,B [:,k]为具有6个元件的阵列,B [K ,:]是具有6个元件的阵列。

(由于正在使用的numpy的阵列型,两个B [:,k]和乙[K ,:]返回的形状N A秩1阵列)

NumPy的自动改变大小相匹配:

  1. 第一B [:,k]被加入到B [K ,:]以与6种元素的中间阵列结果。 (这是不是你打算什么)
  2. 第二这个6元件阵列由6矩阵通过重复行广播到6
  3. 原始矩阵和该广播矩阵的第三最小计算。

这意味着你的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,:])

矩阵类型使用更严格的规则,广播因此,在这种情况下:

  1. A [:,k]被重复列扩展为6×6矩阵
  2. 阿[K ,:]由6矩阵通过重复行扩展为6
  3. 所广播的矩阵加在一起由6矩阵作出6
  4. 最小的应用


Answer 2:

通常你想,因为你认为它是运行速度太慢向量化代码。
如果你的代码是太慢了,那么我可以告诉你,正确的索引将使其更快。
取而代之的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

在代码中始终做到这一点 - 我坚信,已经解决您的性能问题!

话说回来...

......这是我拿上如何向量化

for k in range(num_v):
    numpy.minimum(A, np.add.outer(A[:,k], A[k,:]), A)
return A

numpy.minimum将比较两个数组,并返回逐元素两个元素的小。 如果您传递第三个参数将采取输出。 如果这是一个输入阵列的整个操作是在适当位置。

正如彼得·德Rivay解释说,不存在与广播解决方案的一个问题 - 但在数学上你想要做的是某种在另外两个向量的外积的。 因此,你可以在附加功能使用外操作。

NumPy的的二进制ufuncs有特殊的方法进行某些特殊类型的矢量运算喜欢降低,积累,总结和外部。



文章来源: How to vectorize this python code?