在 Numpy 中比较两个 3D 矩阵的数组,无需 for 循环

Rik*_*son 5 python arrays comparison numpy vectorization

所有 Numpy 专家,这对你们来说可能非常简单。这个问题应该存在,但我没有找到确切的解决方案。类似的事情是按 NumPy 中的出现情况按行比较两个矩阵,并且Numpy 将数组一次与多个标量进行比较,但不完全在那里。

我需要计算numpy.array_equal多维数组,但我很确定我不需要使用双 for 循环。但是,如果我使用双 for 循环进行计算,它将如下所示:

M = numpy.array(
     [
         [
            [1,2,3],
            [1,3,4]
         ],
         [
            [3,4,5],
            [1,2,3]
         ],
         [
            [1,2,3],
            [1,3,4]
         ]
     ])

result = np.zeros((M.shape[0], M.shape[0]))
for i in range(M.shape[0]):
    for j in range(M.shape[0]):
        result[i,j] = numpy.array_equal(M[i], M[j])
Run Code Online (Sandbox Code Playgroud)

我最终应该得到一个M.shape[0]^2大的真值表,其中至少对角线是正确的。

Div*_*kar 2

broadcasting将输入扩展为两个版本后的杠杆,4D以便我们可以比较成对数组块,同时保持最后两个轴对齐 -

\n\n
result = (M[:,None] == M).all((2,3))\n
Run Code Online (Sandbox Code Playgroud)\n\n

我们可以使用最后两个轴作为输入将其扩展到通用的 n 维数组情况.all()-

\n\n
(M[:,None] == M).all((-2,-1))\n
Run Code Online (Sandbox Code Playgroud)\n\n

杠杆作用views内存效率更高、性能更高的内存 -

\n\n
# /sf/answers/3149930661/ @Divakar\ndef view1D(a): # a is array\n    a = np.ascontiguousarray(a)\n    void_dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1]))\n    return a.view(void_dt).ravel()\n\nM1D = view1D(M.reshape(M.shape[0],-1))\nresult = M1D[:,None] == M1D\n
Run Code Online (Sandbox Code Playgroud)\n\n

大阵列上的计时 -

\n\n
In [48]: np.random.seed(0)\n    ...: M = np.random.randint(0,10,(100,100,100))\n\nIn [49]: %timeit (M[:,None] == M).all((-2,-1))\n10 loops, best of 3: 92.2 ms per loop\n\nIn [50]: %%timeit \n    ...: M1D = view1D(M.reshape(M.shape[0],-1))\n    ...: M1D[:,None] == M1D\n1000 loops, best of 3: 627 \xc2\xb5s per loop\n
Run Code Online (Sandbox Code Playgroud)\n\n

原来的一个——

\n\n
In [54]: %%timeit\n    ...: result = np.zeros((M.shape[0], M.shape[0]))\n    ...: for i in range(M.shape[0]):\n    ...:     for j in range(M.shape[0]):\n    ...:         result[i,j] = numpy.array_equal(M[i], M[j])\n10 loops, best of 3: 125 ms per loop\n
Run Code Online (Sandbox Code Playgroud)\n\n

结论是 - 删除循环,但要注意内存使用情况。如果可能的话,找到其他方法来保持向量化和内存效率。

\n