【问题标题】:Replace all elements of Python NumPy Array that are greater than some value替换大于某个值的 Python NumPy 数组的所有元素
【发布时间】:2013-11-09 02:30:00
【问题描述】:

我有一个 2D NumPy 数组,想用 255.0 替换其中大于或等于阈值 T 的所有值。据我所知,最基本的方法是:

shape = arr.shape
result = np.zeros(shape)
for x in range(0, shape[0]):
    for y in range(0, shape[1]):
        if arr[x, y] >= T:
            result[x, y] = 255
  1. 执行此操作的最简洁和 Pythonic 的方法是什么?

  2. 是否有更快(可能不那么简洁和/或不那么 Pythonic)的方法来做到这一点?

这将是人体头部 MRI 扫描的窗口/水平调整子程序的一部分。二维numpy数组是图像像素数据。

【问题讨论】:

标签: python arrays numpy replace conditional-statements


【解决方案1】:

np.where() 效果很好!

np.where(arr > 255, 255, arr)

示例:

FF = np.array([[0, 0],
              [1, 0],
              [0, 1],
              [1, 1]])
np.where(FF == 1, '+', '-')
Out[]: 
array([['-', '-'],
       ['+', '-'],
       ['-', '+'],
       ['+', '+']], dtype='<U1')

【讨论】:

    【解决方案2】:

    让我们假设您有一个 numpy 数组,其中包含从 0 一直到 20 的值,并且您想用 0 替换大于 10 的数字

    import numpy as np
    
    my_arr = np.arange(0,21) # creates an array
    my_arr[my_arr > 10] = 0 # modifies the value
    

    但请注意,这将修改原始数组以避免覆盖原始数组尝试使用arr.copy() 创建原始数组的新分离副本并进行修改。

    import numpy as np
    
    my_arr = np.arange(0,21)
    my_arr_copy = my_arr.copy() # creates copy of the orignal array
    
    my_arr_copy[my_arr_copy > 10] = 0 
    

    【讨论】:

      【解决方案3】:

      另一种方法是使用 np.place 进行就地替换并适用于多维数组:

      import numpy as np
      
      # create 2x3 array with numbers 0..5
      arr = np.arange(6).reshape(2, 3)
      
      # replace 0 with -10
      np.place(arr, arr == 0, -10)
      

      【讨论】:

      • 这是我使用的解决方案,因为它是我遇到的第一个。我想知道这与上面选择的答案是否有很大区别。你怎么看?
      • 在我非常有限的测试中,我上面带有 np.place 的代码运行速度比接受的答案的直接索引方法慢 2 倍。这令人惊讶,因为我认为 np.place 会更加优化,但我猜他们可能在直接索引上投入了更多工作。
      • 在我的情况下,np.place 也比内置方法慢,尽管 this 评论中声称相反。
      【解决方案4】:

      我认为最快和最简洁的方法是使用 NumPy 的内置 Fancy 索引。如果您有一个名为 arrndarray,则可以将所有元素 &gt;255 替换为值 x,如下所示:

      arr[arr > 255] = x
      

      我在我的机器上使用 500 x 500 的随机矩阵运行此程序,将所有 >0.5 的值替换为 5,平均耗时 7.59 毫秒。

      In [1]: import numpy as np
      In [2]: A = np.random.rand(500, 500)
      In [3]: timeit A[A > 0.5] = 5
      100 loops, best of 3: 7.59 ms per loop
      

      【讨论】:

      • 请注意,这会修改现有数组 arr,而不是像在 OP 中那样创建 result 数组。
      • 有没有办法通过不修改A而是创建一个新数组来做到这一点?
      • 如果我们想改变给定 n 的倍数的索引值,例如 a[2],a[4],a[6],a[8].. ... 对于 n=2?
      • 注意:如果数据在 python 列表中,这不起作用,它必须在 numpy 数组中 (np.array([1,2,3])
      • 是否可以使用此索引无条件地更新每个值?我想这样做:array[ ? ] = x,将每个值设置为 x。其次,是否可以执行多个条件,例如:array[ ? ] = 255 if array[i] &gt; 127 else 0 我想优化我的代码,目前正在使用列表理解,这比这种花哨的索引要慢得多。
      【解决方案5】:

      您还可以使用&amp;|(和/或)以获得更大的灵活性:

      5 到 10 之间的值:A[(A&gt;5)&amp;(A&lt;10)]

      大于 10 或小于 5 的值:A[(A&lt;5)|(A&gt;10)]

      【讨论】:

        【解决方案6】:

        我认为使用where 函数可以最快地实现这一点:

        例如在 numpy 数组中查找大于 0.2 的项目并将其替换为 0:

        import numpy as np
        
        nums = np.random.rand(4,3)
        
        print np.where(nums > 0.2, 0, nums)
        

        【讨论】:

          【解决方案7】:

          您可以考虑使用numpy.putmask

          np.putmask(arr, arr>=T, 255.0)
          

          这是与 Numpy 的内置索引的性能比较:

          In [1]: import numpy as np
          In [2]: A = np.random.rand(500, 500)
          
          In [3]: timeit np.putmask(A, A>0.5, 5)
          1000 loops, best of 3: 1.34 ms per loop
          
          In [4]: timeit A[A > 0.5] = 5
          1000 loops, best of 3: 1.82 ms per loop
          

          【讨论】:

          • 我已经测试了上限0.5而不是5的代码,并且indexingnp.putmask好大约两倍。
          【解决方案8】:

          由于您实际上想要一个不同的数组,即 arr 其中 arr &lt; 255255 否则,这可以简单地完成:

          result = np.minimum(arr, 255)
          

          更一般地,对于下限和/或上限:

          result = np.clip(arr, 0, 255)
          

          如果您只想访问超过 255 的值或更复杂的值,@mtitan8 的答案更笼统,但np.clipnp.minimum(或np.maximum)对您的情况更好更快:

          In [292]: timeit np.minimum(a, 255)
          100000 loops, best of 3: 19.6 µs per loop
          
          In [293]: %%timeit
             .....: c = np.copy(a)
             .....: c[a>255] = 255
             .....: 
          10000 loops, best of 3: 86.6 µs per loop
          

          如果您想就地执行(即修改 arr 而不是创建 result),您可以使用 np.minimumout 参数:

          np.minimum(arr, 255, out=arr)
          

          np.clip(arr, 0, 255, arr)
          

          out= 名称是可选的,因为参数的顺序与函数定义的顺序相同。)

          对于就地修改,布尔索引加快了很多(无需单独制作然后修改副本),但仍然不如minimum快:

          In [328]: %%timeit
             .....: a = np.random.randint(0, 300, (100,100))
             .....: np.minimum(a, 255, a)
             .....: 
          100000 loops, best of 3: 303 µs per loop
          
          In [329]: %%timeit
             .....: a = np.random.randint(0, 300, (100,100))
             .....: a[a>255] = 255
             .....: 
          100000 loops, best of 3: 356 µs per loop
          

          为了比较,如果你想用最小值和最大值限制你的值,没有clip,你必须这样做两次,类似于

          np.minimum(a, 255, a)
          np.maximum(a, 0, a)
          

          或者,

          a[a>255] = 255
          a[a<0] = 0
          

          【讨论】:

          • 非常感谢您的完整评论,但是在这种情况下,np.clip 和 np.minimum 似乎不是我需要的,在 OP 中您会看到阈值 T 和替换值(255) 不一定是相同的数字。但是,我仍然为彻底性投了赞成票。再次感谢。
          • 如果我们想改变给定 n 的倍数的索引值,例如 a[2],a[4],a[6],a[8].. ... 对于 n=2?
          • @lavee_singh,为此,您可以使用切片的第三部分,这通常被忽略:a[start:stop:step] 为您提供从startstop 的数组元素,但是而不是每个元素,它只需要每个step(如果忽略,默认为1)。因此,要将所有偶数设置为零,您可以执行 a[::2] = 0
          • 谢谢我需要像这样的东西,尽管我知道它适用于简单的列表,但我不知道它是否或如何适用于 numpy.array。
          • 令人惊讶的是,在我的调查中,a = np.maximum(a,0)np.maximum(a,0,out=a) 快。
          猜你喜欢
          • 1970-01-01
          • 2016-05-03
          • 2019-12-08
          • 2017-11-13
          • 1970-01-01
          • 2020-06-07
          • 2018-01-30
          • 1970-01-01
          相关资源
          最近更新 更多