从python中的矩阵对所有组合进行矢量化角度计算

时间:2019-11-25 08:16:54

标签: python numpy matrix optimization vectorization

请参见下面的修改

我有一个相当大的矩阵x(3xn,n >> 1000),每列的关系信息有限。 从这个矩阵x,我需要找到两列的最大角度和相应的索引。 目前,我正在使用两个for循环,这需要很长时间,请参见下面的代码。

我知道我可以将向量的范数向量化,例如通过np.linalg.norm(x, axis=0)。 另外,我发现了一些有关如何对点积[here]进行矢量化的信息。 但是,这只会计算每列之间的点积,而不计算列1和3之间的点积。

有没有一种方法可以优化甚至向量化问题?

import numpy as np

# Calculate the max angle between two vectors
len_x = 1000
x = np.random.rand(3,len_x) # 3xn matrix

ang_max = 0 # maximum angle
n_max   = 0 # n-index of maximum angle
m_max   = 0 # m-index of maximum angle

for n in range(len_x - 1):
     vn = np.array([x[0][n], \
                    x[1][n], \
                    x[2][n]])
     for m in range(n + 1, len_x):
         vm = np.array([x[0][m], \
                        x[1][m], \
                        x[2][m]])

         ang = np.arccos(np.dot(vn,vm)/(np.linalg.norm(vn)*np.linalg.norm(vm)))

         if ang > ang_max:
             ang_max = ang
             n_max = n
             m_max = m

编辑:

使用np.einsum,我可以向量化内部循环。 至少在我的测试案例中,这将执行时间缩短了44倍(从31.98 s降至0.725 s)。 这是一个重大的改进,但是我觉得对外部循环进行矢量化处理可能会由于类似的原因而使速度进一步提高。 因此,我不会将问题标记为已回答,因为外循环也不是矢量化的log。

import numpy as np

# Calculate the max angle between two vectors
len_x = 1000
x = np.random.rand(3,len_x) # 3xn matrix

ang_max = 0 # maximum angle
n_max   = 0 # n-index of maximum angle
m_max   = 0 # m-index of maximum angle

vm      = np.array(x)
vm_norm = np.linalg.norm(vm, axis=0)

for n in range(len_x - 1):
    vn = np.array([float(x[n]) - xs, \
                   float(y[n]) - ys, \
                   float(z[n]) - zs])
    ang = np.arccos(np.divide(np.einsum('ij,ij->j', vn[:,None], vm[:,:,0]),(np.linalg.norm(vn)*vm_norm)[:,0]))
    maxang = max(ang)

    if maxang > ang_max:
        ang_max = maxang
        n_max = n
        m_max = np.where(ang == maxang)[0][0]

1 个答案:

答案 0 :(得分:0)

结果,我正在寻找的实际上是[Gramian Matrix],一个矩阵,其元素都是内部乘积的所有可能组合。就我而言,它转换为以下代码:

import numpy as np

# Calculate the max angle between two vectors
len_x = 1000
x = np.random.rand(3,len_x) # 3xn matrix

ang_max = 0 # maximum angle
n_max   = 0 # n-index of maximum angle
m_max   = 0 # m-index of maximum angle

vm      = np.array(x)
vm_norm = np.linalg.norm(vm, axis=0)

ang = np.arccos(np.divide(vm.T.dot(vm), (vm_norm.dot(vm_norm))))

ang_max = np.amax(ang)
argw    = np.argwhere(ang == np.amax(ang))
n_max   = argw[0, 0]
m_max   = argw[0, 1]

该代码使我的性能又提高了约4倍,使执行时间降低至约0.2 s。

现在,由于内积是对称的,因此vm.dot(vm)的一半计算是多余的。我不确定如何在不增加太多复杂性的情况下进一步优化这种情况。但是,我有一种强烈的感觉,numpy足够聪明,可以检测到冗余并对其进行自动优化。