Python numpy数组中的快速值交换
这应该很简单,但对我来说似乎花费了大量的时间:我有一个只有两个值的numpy数组(例如0和255),我想用这种方式反转矩阵,所有值交换(0变成255,反之亦然)。矩阵大约有2000个大条目,所以这是一项严肃的工作!我首先尝试了numpy.invert方法,这与我的预期不完全一样。因此,我试图通过“存储”这些值并覆盖它们来实现这一点:Python numpy数组中的快速值交换,python,arrays,numpy,Python,Arrays,Numpy,这应该很简单,但对我来说似乎花费了大量的时间:我有一个只有两个值的numpy数组(例如0和255),我想用这种方式反转矩阵,所有值交换(0变成255,反之亦然)。矩阵大约有2000个大条目,所以这是一项严肃的工作!我首先尝试了numpy.invert方法,这与我的预期不完全一样。因此,我试图通过“存储”这些值并覆盖它们来实现这一点: for i in range(array.length): array[i][array[i]==255]=1 ar
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循环?)。如果我将其实现为多线程计算,每个线程“反转”一个更小的子数组,会更快吗?或者还有其他更方便的方法吗?要交换0和255,如果数据类型是整数类型之一,可以使用XOR
array ^= 255
“我首先尝试了numpy.invert方法,这与我的预期不完全一样。”
Numpy.invert正是您所需要的。你能描述一下发生了什么事吗?您是否使用无符号字节进行存储,而不是使用有符号数据类型或整数
Unsigned byte+numpy.invert应该完全满足您的要求
[您还应该看到使用无符号字节而不是更长或有符号数据类型的numpy的性能更快]除了@JanneKarila和@EOL的优秀建议之外,值得展示一种更有效的使用掩码进行交换的方法 如果您的比较比简单地交换两个值更复杂,那么使用布尔掩码通常更有用,但您的示例以次优方式使用它 目前,您正在制作上述示例中布尔“掩码”数组的多个临时副本(例如,
数组[i]==blah
),并执行多个赋值。您可以通过只创建一次“掩码”布尔数组并反转它来避免这种情况
如果您有足够的ram用于临时复制(ofbool
dtype),请尝试以下操作:
mask = (data == 255)
data[mask] = 0
data[~mask] = 255
for i in range(len(array)):
mask = (array[i] == 255)
array[mask] = 0
array[~mask] = 255
或者(等效地)可以使用numpy。其中
:
data = numpy.where(data == 255, 0, 255)
如果您使用循环来避免生成完整的临时副本,并且需要保留ram,请将循环调整为类似以下内容:
mask = (data == 255)
data[mask] = 0
data[~mask] = 255
for i in range(len(array)):
mask = (array[i] == 255)
array[mask] = 0
array[~mask] = 255
所有这些都已经说过,在这种情况下,减法或异或都是可行的方法,特别是如果您在适当的位置执行操作的话 您只需执行以下操作:
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)
,用于交换两个整数a
和b
两种方法之间的执行时间相似(通过IPython使用200×200×200的uint8
整数数组):
如果您的数组是类型
uint8
,arr\u inversed=~a
需要相同的时间来交换0和255(~
运算符反转所有位),并且不太通用,因此不值得(使用200×200×200数组进行测试)。这只适用于uint8
,通常不适用于无符号整数。OP的数组可能不是uint8
。你好,乔。谢谢你的评论,但实际上我没有说“一般无符号整数”,我说的是无符号字节,即uint8。如果他只存储0和255,那么OP可能正在使用uint8。不过,将它们打包成1/0更有意义。@那个家伙欢迎来到!你是对的,但@Joe只是想澄清一下,因为OP(或我自己,例如)可能不清楚你的确切意思。在回答中尽量明确,例如说“如果您使用的是无符号字节(uint8
),则反转应该有效,因此可能您使用的是有符号数据类型或整数。”顺便说一句,要通知Joe,您必须在他的名字前面加@,如@Joe。这仅在数组包含整数时有效,这从问题上看并不明显。不过,没有否决票。:)事实上,最简单的想法就是最有效的想法!谢谢!旁注:我建议不要使用array
作为数组的名称:NumPy用户希望array
的意思是NumPy.array
。此外,当您在numpy导入*(或pylab导入*)的之后将代码粘贴到shell中时,您的变量会阴影numpy的数组
。我在这里使用数组只是为了清除输入类型;)如果内存是一个问题,np.subtract(255,arr,out=arr)
将就地执行您的方法。这两种方法都避免了OP使用==1
掩码进行第三次复制。