我有一个2D numpy数组,其中包含'n'个唯一值。 我想生成一个二进制矩阵,其中所有值都替换为 'zero'和我指定的值被指定为'one'。
例如,我有一个如下数组,我想要所有实例 35被指定为'one':
array([[12, 35, 12, 26],
[35, 35, 12, 26]])
我想获得以下输出:
array([[0, 1, 0, 0],
[1, 1, 0, 0]])
在Python中最有效的方法是什么?
答案 0 :(得分:8)
import numpy as np
x = np.array([[12, 35, 12, 26], [35, 35, 12, 26]])
(x == 35).astype(int)
会给你:
array([[0, 1, 0, 0],
[1, 1, 0, 0]])
numpy中的==运算符执行逐元素比较,当将布尔值转换为整数时,True编码为1,False编码为0。
答案 1 :(得分:4)
import numpy as np
x = np.array([[12, 35, 12, 26], [35, 35, 12, 26]])
(x == 35) + 0
数组([[0,1,0,0], [1,1,0,0]])
答案 2 :(得分:4)
与所有其他解决方案相比,更优雅的方法是使用np.isin()
>>> arr
array([[12, 35, 12, 26],
[35, 35, 12, 26]])
# get the result as binary matrix
>>> np.isin(arr, 35).astype(np.uint8)
array([[0, 1, 0, 0],
[1, 1, 0, 0]])
np.isin()
将返回带有True
值的布尔掩码,其中给定元素(此处为35
)出现在原始数组中,{{1在其他地方。
另一种变体是使用数据类型为np.asarray()
的np.uint8
转换布尔结果,以提高速度:
False
通过将布尔结果显式地转换为uint8
,我们可以获得超过 3x更好的性能。 (感谢@Divakar指出这一点!)见下面的时间:
In [18]: np.asarray(np.isin(x, 35), dtype=np.uint8)
Out[18]:
array([[0, 1, 0, 0],
[1, 1, 0, 0]], dtype=uint8)
如果您想要真正的战马,请使用numexpr
,如下所示:
# setup (large) input array
In [3]: x = np.arange(25000000)
In [4]: x[0] = 35
In [5]: x[1000000] = 35
In [6]: x[2000000] = 35
In [7]: x[-1] = 35
In [8]: x = x.reshape((5000, 5000))
# timings
In [20]: %timeit np.where(x==35, 1, 0)
427 ms ± 25.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [21]: %timeit (x == 35) + 0
450 ms ± 72 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [22]: %timeit (x == 35).astype(np.uint8)
126 ms ± 37.6 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
# the fastest choice to go for!
In [23]: %timeit np.isin(x, 35).astype(np.uint8)
115 ms ± 2.21 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [24]: %timeit np.asarray(np.isin(x, 35), dtype=np.uint8)
117 ms ± 2.91 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
这是 ca。比使用基于NumPy的计算的最慢方法快20倍 。
最后,如果 views 没问题,我们可以使用NumPy方法获得如此疯狂的加速。
In [8]: import numexpr as ne
In [9]: %timeit ne.evaluate("x==35").astype(np.uint8)
23 ms ± 2.69 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
(再次感谢@Divakar提及these super nice tricks!)
答案 3 :(得分:2)
如果你的数组是一个numpy数组,那么你可以使用数组上的'=='运算符来返回一个布尔数组。然后使用astype功能将其转换为0和1。
import numpy as np
my_array = np.array([[12, 35, 12, 26],
[35, 35, 12, 26]])
indexed = (my_array == 35).astype(int)
print indexed
答案 4 :(得分:2)
我喜欢@yuji approach。很优雅!
为了多样性,这里是另一个需要大量劳动的答案......
>>> from numpy import np
>>> x = np.array([[12, 35, 12, 26],[35, 35, 12, 26]])
>>> x
array([[12, 35, 12, 26],
[35, 35, 12, 26]])
>>> y=np.zeros(x.shape)
>>> y[np.where(x==35)] = np.ones(len(np.where(x==35)[0]))
>>> y
array([[ 0., 1., 0., 0.],
[ 1., 1., 0., 0.]])
>>>
答案 5 :(得分:2)
另一种选择是使用np.where
;这个解决方案慢于@yuji's solution(参见下面的时间),但如果你想做任何其他事情,除了放入零和一个(见下面的例子),它会更灵活。
import numpy as np
x = np.array([[12, 35, 12, 26], [35, 35, 12, 26]])
np.where(x==35, 1, 0)
产生
array([[0, 1, 0, 0],
[1, 1, 0, 0]])
可以像那样读取它,其中x等于35放在1中,其他地方插入0 。
如上所述,您现在具有很大的灵活性,例如,还要做以下事情:
np.where(x==35, np.sqrt(x), x - 3)
array([[ 9. , 5.91607978, 9. , 23. ],
[ 5.91607978, 5.91607978, 9. , 23. ]])
所以在x
等于35
的任何地方,您都会获得平方根,并从所有其他值中减去3
。
时序:
%timeit np.where(x==35, 1, 0)
100000 loops, best of 3: 5.85 µs per loop
%timeit (x == 35).astype(int)
100000 loops, best of 3: 3.23 µs per loop
%timeit np.isin(x, 35).astype(int)
10000 loops, best of 3: 18.7 µs per loop
%timeit (x == 35) + 0
100000 loops, best of 3: 5.85 µs per loop