【问题标题】:Compare two arrays and display the sum of the matches比较两个数组并显示匹配的总和
【发布时间】:2018-03-12 11:34:26
【问题描述】:

我有 2 个形状相同的 numpy 数组。现在我想比较数组1和数组2的值,最后输出条件值== 1的匹配总和。

数组 1:

[1, 0, 1]
[1, 1, 0]
[0, 0, 1]

数组 2:

[0, 1, 1]
[1, 0, 0]
[0, 1, 1]

结果现在应该如下所示:

sum = 3

--------------

我的以下算法正在运行,但不是非常高效和优雅:

k = 0
for i in range(0,array1.shape[0],1):
    for j in range(0, array1.shape[1], 1):

        if array1[i][j] == array2[i][j] and array1[i][j] == 1:
            k = k + 1
        else:
            continue

print k

【问题讨论】:

    标签: python arrays python-2.7 numpy


    【解决方案1】:

    这是结合您的 2 个条件的一种方法。

    import numpy as np
    
    a = np.array([[1, 0, 1],
                  [1, 1, 0],
                  [0, 0, 1]])
    
    b = np.array([[0, 1, 1],
                  [1, 0, 0],
                  [0, 1, 1]])
    
    res = np.sum((a==b) & (a==1))  # 3
    

    说明

    • a==b 返回一个布尔数组,按元素测试 2 个数组之间的相等性。
    • a==1 返回一个布尔数组,测试 a 中的元素是否相等,按元素为 1。
    • & 运算符用于表示两个条件都必须满足。
    • np.sum 适用于布尔数组,因为 boolint 的子类,即 True 可以视为 1,False 可以视为 0。

    【讨论】:

      【解决方案2】:

      如果真的只是二进制数据,你可以这样做

      np.logical_and(a, b).sum()
      3
      

      这应该比(a==b) & (a==1)快得多

      【讨论】:

        【解决方案3】:

        我对上述解决方案做了一些计时......

        第一名:np.logical_and()

        第二名:np.sum(np.multiply())

        第三名:np.sum(arr1 == arr2 & arr1 == 1)

        第四名:基本循环和比较。

        这将输出:

        # Test 1 gives : 15.1819742985
        # Test 2 gives : 14.9471218792
        # Test 3 gives : 6.76537855828
        # Test 4 gives : 9.16029915098
        

        import numpy as np
        import timeit
        
        arr1 = np.array([[1, 0, 1], [1, 1, 0], [0, 0, 1]])
        arr2 = np.array([[0, 1, 1], [1, 0, 0], [0, 1, 1]])
        numberIterations = 1000000
        
        def test_1(arr1, arr2):
            return np.sum((arr1 == arr2) & (arr1 == 1))
        
        def test_2(arr1, arr2):
            summed = 0
            for a1, a2 in zip(arr1, arr2):
                for c1, c2 in zip(a1, a2):
                    if c1 == c2 and c1 == 1:
                        summed += 1
            return summed
        
        def test_3(arr1, arr2):
            return np.logical_and(arr1, arr2).sum()
        
        def test_4(arr1, arr2):
            return np.sum(np.multiply(arr1, arr2))  
        
        # Testing time.
        # Test 1
        time1 = timeit.timeit(stmt='test_1(arr1, arr2)',
                            setup='from __main__ import test_1, arr1, arr2',
                            number=numberIterations)
        
        # Test 2
        time2 = timeit.timeit(stmt='test_2(arr1, arr2)',
                            setup='from __main__ import test_2, arr1, arr2',
                            number=numberIterations)
        
        # Test 3
        time3 = timeit.timeit(stmt='test_3(arr1, arr2)',
                            setup='from __main__ import test_3, arr1, arr2',
                            number=numberIterations)
        
        # Test 4
        time4 = timeit.timeit(stmt='test_4(arr1, arr2)',
                            setup='from __main__ import test_4, arr1, arr2',
                            number=numberIterations)
        
        # Printing results.
        print 'Test 1 gives : {}'.format(time1)
        print 'Test 2 gives : {}'.format(time2)
        print 'Test 3 gives : {}'.format(time3)
        print 'Test 4 gives : {}'.format(time4)
        

        【讨论】:

        • 赞成,因为我支持分析,尽管这是我见过的最令人困惑的分析脚本。
        • 哈哈,对不起。我已经习惯了计时。如果您有任何链接可以帮助我通过这些测试改进我的代码格式,我会很高兴阅读它们。 :)
        • @user2699 尝试改进格式,但我仍在接受建议
        • 不用担心,这里的东西很棒,我只花了一分钟时间将输出时间与运行代码的时间联系起来。
        • 虽然我会补充,如果您使用ipython 控制台,您可以使用魔术命令%timeit 运行timeit。所以 test1 会变成%timeit np.sum((arr1 == arr2) & (arr1 == 1))。您不会得到设置代码,但通常这不是问题,它提供了很好的时间格式,设置非常简单。
        【解决方案4】:
        >>> import numpy as np
        >>> a=np.array([[1,0,1],[1,1,0],[0,0,1]])
        >>> b=np.array([[0,1,1],[1,0,0],[0,1,1]])
        >>> a==b
        array([[False, False,  True],
               [ True, False,  True],
               [ True, False,  True]], dtype=bool)
        >>> c=np.array(a==b, dtype=int)
        >>> c
        array([[0, 0, 1],
               [1, 0, 1],
               [1, 0, 1]])
        >>> np.sum(c)
        5
        >>> d=np.array(a*b, dtype=int)
        >>> d
        array([[0, 0, 1],
               [1, 0, 0],
               [0, 0, 1]])
        >>> np.sum(d)
        3
        

        【讨论】:

          【解决方案5】:

          如果你的矩阵中只有 0 和 1

          import numpy as np 
          
          ar_1=np.array([[1, 0, 1],
          [1, 1, 0],
          [0, 0, 1]])
          
          ar_2 = np.array([[0, 1, 1],
          [1, 0, 0],
          [0, 1, 1]])
          
          np.sum(np.multiply(ar_1,ar_2))
          

          np.multiply 将是元素乘法。只有当给定的两个参数都是一个时,才会给你 1。

          没有轴的np.sum将对矩阵的所有元素求和

          【讨论】:

            【解决方案6】:

            这里有四种更快速的方法:

            1)np.dot:

            np.dot(a.ravel(), b.ravel())
            # 3
            

            2)np.bincount:

            np.bincount(a.ravel(), b.ravel())[1]
            # 3.0
            

            3)np.count_nonzero:

            np.count_nonzero(a * b)
            # 3
            

            4)np.repeat:

            np.count_nonzero(a.ravel().repeat(b.ravel()))
            # 3
            

            借用@IMCoins 的测试脚本我得到

            Test 1 gives : 6.34505105019
            Test 2 gives : 7.32884097099
            Test 3 gives : 3.29451298714
            Test 4 gives : 3.76608014107
            Test 5 gives : 1.28572297096    <- np.dot
            Test 6 gives : 1.3145699501     <- np.bincount
            Test 7 gives : 0.984617948532   <- np.count_nonzero
            Test 8 gives : 1.06798291206    <- np.repeat
            

            如果我使用更大的数组 (np.tile(arr[1/2], (100, 100))) 和更少的迭代,这将变成:

            Test 1 gives : 0.253939151764
            Test 2 gives : 34.9494478703
            Test 3 gives : 0.190597057343
            Test 4 gives : 0.139708995819
            Test 5 gives : 0.0751769542694
            Test 6 gives : 0.382376909256
            Test 7 gives : 0.239590883255
            Test 8 gives : 0.335343122482
            

            【讨论】:

            • 所以基本上如果你想快点,最好避免乘法和加法——除非你让BLAS去做。
            • @DanielF 不确定,我不得不承认我发现细节相当混乱。但我认为你对 blas 的看法是正确的。
            猜你喜欢
            • 2023-03-07
            • 1970-01-01
            • 2023-03-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-01-24
            相关资源
            最近更新 更多