【问题标题】:numpy swap multiple elements in an arraynumpy 交换数组中的多个元素
【发布时间】:2019-04-22 07:18:24
【问题描述】:

我有一个 numpy 数组,其中包含 1 和 0 的随机分布。我想用 0 替换所有的 1,用 1 替换所有的零。

arr[arr == 0] = 2
arr[arr == 1] = 0
arr[arr == 2] = 1

我目前不得不使用一个临时值(在这种情况下为 2),以避免所有 0 变为 1,然后使整个数组充满 0。 有没有更优雅/更有效的方法来做到这一点?

【问题讨论】:

    标签: python arrays numpy indexing


    【解决方案1】:

    您可以在覆盖任何值之前计算和存储布尔索引器:

    ones = a == 1
    zeros = a == 0
    
    a[ones] = 0
    a[zeros] = 1
    

    如果您的值不是01,该解决方案也有效。


    如果您不需要就地解决方案,可以使用np.where

    a = np.where(ones, 0, np.where(zeros, 1, a))
    

    【讨论】:

      【解决方案2】:

      这是一个针对您的问题非常具体的解决方案,但也应该非常快。给定数组:

      >>> a
      array([[1, 0, 0, 1],
             [1, 1, 1, 0]])
      

      您可以从所有值中减去 1 并乘以负 1:

      >>> (a-1)*-1
      array([[0, 1, 1, 0],
             [0, 0, 0, 1]])
      

      【讨论】:

      • (a - 1) * -1 分发到 -a + 11 - a 更清晰(也更快)
      【解决方案3】:

      为您的特定值按位异或 1。

      In [19]: a=np.random.randint(2, size=10)
      
      In [18]: a
      Out[18]: array([1, 1, 1, 1, 1, 1, 0, 0, 1, 1])
      
      In [19]: a^1
      Out[19]: array([0, 0, 0, 0, 0, 0, 1, 1, 0, 0])
      

      一个更通用的 int 类型解决方案。

      In [62]: convert=np.array([1,0])
      
      In [63]: convert[a]
      Out[63]: array([0, 0, 0, 0, 0, 0, 1, 1, 0, 0])
      

      更改“convert”数组的内容意味着可以映射一系列值。结果使用数组'a'的内容作为数组'convert'的索引。

      【讨论】:

      • 很好的解决方案!您在第二个中使用的索引逻辑是花哨的索引,还是使用另一个名称?
      • numpy 文档将其显示为高级索引 -> 整数数组索引。 link。这两种方法都来自使用 Forth 而不是 Python/numpy 的经验。
      【解决方案4】:

      给定

      >>> a
      array([[1, 0, 0, 1],
             [1, 1, 1, 0]])
      

      你可以使用numpy.where

      >>> np.where(a == 0, 1, 0) # read as (if, then, else)
      array([[0, 1, 1, 0],
             [0, 0, 0, 1]])
      

      ...或者否定a并进行一些类型转换。

      >>> (~a.astype(bool)).astype(int)
      array([[0, 1, 1, 0],
             [0, 0, 0, 1]])
      

      (IPython)时间:差别不大。

      >>> a = np.eye(1000, dtype=int)
      >>> %timeit np.where(a == 0, 1, 0)
      1.56 ms ± 2.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
      >>> %timeit (~a.astype(bool)).astype(int)
      1.74 ms ± 87.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
      

      其他人回答的时间:

      >>> %timeit a^1 # Tls Chris
      920 µs ± 31.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
      >>> %timeit np.array([1, 0])[a] # Tls Chris
      1.4 ms ± 102 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
      >>> %timeit (a - 1)*-1 # sacul
      1.57 ms ± 13.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
      >>> %timeit 1 - a # user3483203
      905 µs ± 2.16 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
      

      我的意见:a^11 - a 干净、优雅、快速。使用 np.where 可以处理您可能想要交换的任何值。

      【讨论】:

        【解决方案5】:

        如果一个高效的解决方案比一个优雅的解决方案更重要,您可以编写一个非常简单的Numba 解决方案。

        示例

        import numba as nb
        import numpy as np
        
        @nb.njit()
        def nb_where(arr):
          for i in range(arr.shape[0]):
            for j in range(arr.shape[1]):
              if arr[i,j]==1:
                arr[i,j] = 0
              else:
                arr[i,j] = 1
          return arr
        

        时间

        a = np.eye(1000, dtype=int)
        np.where(a == 0, 1, 0) #timgeb    -> 2.06ms 
        a^1                    #Tls Chris -> 1.31ms 
        nb_where(a)                       -> 152 µs
        

        【讨论】:

          猜你喜欢
          • 2015-04-22
          • 1970-01-01
          • 2019-03-30
          • 1970-01-01
          • 2023-03-14
          • 1970-01-01
          • 2018-08-14
          • 1970-01-01
          • 2012-09-21
          相关资源
          最近更新 更多