numpy数组中的快速值交换

时间:2013-04-09 12:00:11

标签: python arrays numpy

所以,这应该是非常容易的,但是对我来说似乎需要花费大量时间:我有一个只有两个值的numpy数组(例如0和255)我想要反转矩阵以这种方式,所有值交换(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 个答案:

答案 0 :(得分:6)

除了@ JanneKarila和@ EOL的优秀建议外,还有必要展示一种更有效的方法来使用掩码进行交换。

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

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

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

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

所有这一切,无论是减法还是XOR都是这种情况下的方法,特别是如果你就地进行操作!

答案 1 :(得分:4)

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

array ^= 255

答案 2 :(得分: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

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

>>> 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阵列测试)。

答案 3 :(得分:1)

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

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

无符号字节+ numpy.invert应该完全符合您的要求。

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