Python 检查numpy数组是否为二进制数组的快速方法(仅包含0和1)

Python 检查numpy数组是否为二进制数组的快速方法(仅包含0和1),python,numpy,Python,Numpy,给定一个numpy数组,如何快速判断它是否只包含0和1? 是否有任何实施方法?很少有方法- ((a==0) | (a==1)).all() ~((a!=0) & (a!=1)).any() np.count_nonzero((a!=0) & (a!=1))==0 a.size == np.count_nonzero((a==0) | (a==1)) 运行时测试- In [313]: a = np.random.randint(0,2,(3000,3000)) # Only 0s

给定一个numpy数组,如何快速判断它是否只包含0和1? 是否有任何实施方法?

很少有方法-

((a==0) | (a==1)).all()
~((a!=0) & (a!=1)).any()
np.count_nonzero((a!=0) & (a!=1))==0
a.size == np.count_nonzero((a==0) | (a==1))
运行时测试-

In [313]: a = np.random.randint(0,2,(3000,3000)) # Only 0s and 1s

In [314]: %timeit ((a==0) | (a==1)).all()
     ...: %timeit ~((a!=0) & (a!=1)).any()
     ...: %timeit np.count_nonzero((a!=0) & (a!=1))==0
     ...: %timeit a.size == np.count_nonzero((a==0) | (a==1))
     ...: 
10 loops, best of 3: 28.8 ms per loop
10 loops, best of 3: 29.3 ms per loop
10 loops, best of 3: 28.9 ms per loop
10 loops, best of 3: 28.8 ms per loop

In [315]: a = np.random.randint(0,3,(3000,3000)) # Contains 2 as well

In [316]: %timeit ((a==0) | (a==1)).all()
     ...: %timeit ~((a!=0) & (a!=1)).any()
     ...: %timeit np.count_nonzero((a!=0) & (a!=1))==0
     ...: %timeit a.size == np.count_nonzero((a==0) | (a==1))
     ...: 
10 loops, best of 3: 28 ms per loop
10 loops, best of 3: 27.5 ms per loop
10 loops, best of 3: 29.1 ms per loop
10 loops, best of 3: 28.9 ms per loop

它们的运行时似乎是可比的。

如果您有权访问Numba(或者cython),您可以编写如下内容,这将大大加快捕获非二进制数组的速度,因为它将使计算短路/立即停止,而不是继续处理所有元素:

import numpy as np
import numba as nb

@nb.njit
def check_binary(x):
    is_binary = True
    for v in np.nditer(x):
        if v.item() != 0 and v.item() != 1:
            is_binary = False
            break

    return is_binary
在纯python中运行它而不借助于像Numba或Cython这样的加速器会使这种方法的速度慢得令人望而却步

时间:

a = np.random.randint(0,2,(3000,3000)) # Only 0s and 1s

%timeit ((a==0) | (a==1)).all()
# 100 loops, best of 3: 15.1 ms per loop

%timeit check_binary(a)
# 100 loops, best of 3: 11.6 ms per loop

a = np.random.randint(0,3,(3000,3000)) # Contains 2 as well

%timeit ((a==0) | (a==1)).all()
# 100 loops, best of 3: 14.9 ms per loop

%timeit check_binary(a)
# 1000000 loops, best of 3: 543 ns per loop

看起来您可以通过以下方式实现:

np.array_equal(a, a.astype(bool))

如果您的数组很大,那么应该避免复制太多的数组(如其他一些答案所示)。因此,它可能会比其他答案稍快一些(但未经测试)。

数据上只有一个循环:

0 <= np.bitwise_or.reduce(ar) <= 1

此方法(始终)分配一个与参数形状相同的临时数组,并且似乎比第一个方法循环数据的速度慢。

numpy unique如何

np.unique(arr)

如果为二进制,则应返回[0,1]。

以下内容应适用于仅包含数字的所有数组

set(array).issubset({0,1}) 
我们可以使用
np.isin()

第1行:
挤压
以展开输入数组,因为我们不想用多维数组处理
np.isin()的复杂性

第二行:
np.isin()
检查输入的所有元素是属于0还是属于1。
np.isin()
返回[真、假、真、真..]的列表。

然后
all()!这也适用于
scipy
稀疏矩阵,只需使用
a.data
代替
a
注意:在上述条件下,全零数组也会返回True如果我没有弄错,当数组的正值大于1时,astype(bool)仍会返回True。因此,这不会给出正确的答案。@MehmetHakanKurtoğlu这正是表达式背后的想法:2将被
True
替换,但之后比较将失败!
set(array).issubset({0,1}) 
input_array = input_array.squeeze(-1)
is_binary   = np.isin(input_array, [0,1]).all()