NumPy:交换数组中多个元素

8

我有一个包含随机分布的1和0的numpy数组。我想将所有的1替换为0,所有的0替换为1。

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

目前我需要使用一个临时值(在这种情况下为2),以避免所有的0变成1,然后使整个数组都充满了0。 是否有更优雅/高效的方法来解决这个问题?

5个回答

4

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

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))

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

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

您可以将所有值减去1并乘以-1:
>>> (a-1)*-1
array([[0, 1, 1, 0],
       [0, 0, 0, 1]])

1
(a - 1) * -1 可以分配为 -a + 11 - a,这样更清晰明了(也更快)。 - user3483203

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'的索引。

好的解决方案!你在第二个方案中使用的索引逻辑是花式索引吗,还是有其他名称? - timgeb
1
NumPy文档将其称为高级索引->整数数组索引。链接。这两种方法都来自使用Forth的经验,而不是Python / numpy。 - Tls Chris

2
给定
>>> 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可以处理任何你想要交换的值。

1
如果效率比优雅更重要,您可以编写一个非常简单的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

Timings

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接