2

所以,这应该很容易,但对我来说似乎需要大量时间:我有一个只有两个值(例如 0 和 255)的 numpy 数组,我想以这种方式反转矩阵,所有值交换(0 变为 255,反之亦然)。矩阵大约有 2000³ 项,所以这是一项严肃的工作!我首先尝试了 numpy.invert 方法,这并不完全符合我的预期。所以我自己尝试通过“存储”这些值然后覆盖它们来做到这一点:

for i in range(array.length):
            array[i][array[i]==255]=1
            array[i][array[i]==0]=255
            array[i][array[i]==1]=0

它的行为符合预期,但需要很长时间(我猜是因为 for 循环?)。如果我将其实现为多线程计算,其中每个线程“反转”一个较小的子数组,那会更快吗?还是有另一种更方便的方法?

4

4 回答 4

6

除了 @JanneKarila 和 @EOL 的出色建议之外,值得展示一种更有效的方法来使用掩码进行交换。

如果您的比较比简单地交换两个值更复杂,则使用布尔掩码通常更有用,但您的示例以次优方式使用它。

目前,您正在制作array[i] == blah上面示例中的布尔“掩码”数组(例如 )的多个临时副本并执行多个分配。您可以通过只制作一次“掩码”布尔数组并将其反转来避免这种情况。

如果您有足够的内存用于临时副本(booldtype),请尝试以下操作:

mask = (data == 255)
data[mask] = 0
data[~mask] = 255

或者(等效地)您可以使用numpy.where

data = numpy.where(data == 255, 0, 255)

如果您使用循环来避免制作完整的临时副本,并且需要保存 ram,请将循环调整为更像这样:

for i in range(len(array)):
     mask = (array[i] == 255)
     array[mask] = 0
     array[~mask] = 255

综上所述,在这种情况下,减法或异或都是可行的方法,尤其是当您就地执行操作时!

于 2013-04-09T12:11:01.837 回答
4

要交换 0 和 255,如果数据类型是整数类型之一,您可以使用 XOR。

array ^= 255
于 2013-04-09T12:02:47.850 回答
4

你可以简单地做:

arr_inverted = 255-arr

这会一一转换所有元素(255 为 0,0 为 255)。更一般地说,如果您只有两个值 a 和 b,则“反转”只需使用(a+b)-arr. 如果这两个值不是整数(如浮点数或复数),这也适用。

正如 Jaime 指出的那样,如果内存是一个问题,则subtract(255, arr, out=arr)交换arr就地的值。

如果您的数组中通常有整数,Janne Karila 的 XOR 就地解决方案具有比上面建议的差异就地解决方案更简洁的优势。它可以概括为arr ^= (a^b),用于交换两个整数ab

两种方法的执行时间相似(使用 200×200×200 的uint8整数数组,通过 IPython):

>>> arr = np.random.choice((0, 255), (200, 200, 200)).astype('uint8')
>>> %timeit np.bitwise_xor(255, arr, out=arr)
100 loops, best of 3: 7.65 ms per loop
>>> %timeit np.subtract(255, arr, out=arr)
100 loops, best of 3: 7.69 ms per loop

如果您的数组类型uint8为,arr_inverted = ~a则交换 0 和 255 需要相同的时间(~运算符反转所有位),并且不太通用,因此不值得(使用 200×200×200 数组进行测试)。

于 2013-04-09T12:13:28.650 回答
1

“我首先尝试了 numpy.invert 方法,这并不完全符合我的预期。”

Numpy.invert 正是您所需要的。你能描述发生了什么吗?您是否使用无符号字节而不是有符号数据类型或整数进行存储?

Unsigned byte + numpy.invert 应该完全符合您的要求。

[您还应该看到使用无符号字节而不是更长或有符号数据类型的 numpy 性能更快]

于 2013-04-09T12:06:49.367 回答