鉴于三个numpy
数组a
,b
和c
(编辑:具有相同的形状/大小),似乎对于非复数数字
a * b * c != 0 # test element-wise whether all are non-zero
给出与以下相同的结果:
np.logical_and(a, np.logical_and(b, c))
第一个版本中是否存在隐藏的陷阱?是否有更简单的方法来测试它?
答案 0 :(得分:3)
鉴于b
和c
持有实数,np.logical_and(b, c)
实际上会涉及到底层转换为布尔值。
我们可以提前进行转换吗?如果是这样,那会有帮助吗?
现在,检查 ALL
相应元素是否为非零的陈述操作等同于检查布尔值是否 ANY
相应的元素为零,即
~((a == 0) + (b==0) + (c==0)
OR
~((a == 0) | (b==0) | (c==0))
此外,与zero
进行比较后,这将涉及预先转换为布尔值,因此可能有助于提高性能。这是涉及的运行时数 -
案例#1:
In [10]: # Setup inputs
...: M, N = 100, 100
...: a = np.random.randint(0,5,(M,N))
...: b = np.random.randint(0,5,(M,N))
...: c = np.random.randint(0,5,(M,N))
...:
In [11]: %timeit np.logical_and(a, np.logical_and(b, c))
...: %timeit a * b * c != 0
...: %timeit ~((a == 0) + (b==0) + (c==0))
...: %timeit ~((a == 0) | (b==0) | (c==0))
...:
10000 loops, best of 3: 96.6 µs per loop
10000 loops, best of 3: 78.2 µs per loop
10000 loops, best of 3: 51.6 µs per loop
10000 loops, best of 3: 51.5 µs per loop
案例#2:
In [12]: # Setup inputs
...: M, N = 1000, 1000
...: a = np.random.randint(0,5,(M,N))
...: b = np.random.randint(0,5,(M,N))
...: c = np.random.randint(0,5,(M,N))
...:
In [13]: %timeit np.logical_and(a, np.logical_and(b, c))
...: %timeit a * b * c != 0
...: %timeit ~((a == 0) + (b==0) + (c==0))
...: %timeit ~((a == 0) | (b==0) | (c==0))
...:
100 loops, best of 3: 11.4 ms per loop
10 loops, best of 3: 24.1 ms per loop
100 loops, best of 3: 9.29 ms per loop
100 loops, best of 3: 9.2 ms per loop
案例#3:
In [14]: # Setup inputs
...: M, N = 5000, 5000
...: a = np.random.randint(0,5,(M,N))
...: b = np.random.randint(0,5,(M,N))
...: c = np.random.randint(0,5,(M,N))
...:
In [15]: %timeit np.logical_and(a, np.logical_and(b, c))
...: %timeit a * b * c != 0
...: %timeit ~((a == 0) + (b==0) + (c==0))
...: %timeit ~((a == 0) | (b==0) | (c==0))
...:
1 loops, best of 3: 294 ms per loop
1 loops, best of 3: 694 ms per loop
1 loops, best of 3: 268 ms per loop
1 loops, best of 3: 268 ms per loop
似乎comparison to zero approach
有很好的利益百分比!
答案 1 :(得分:3)
一些观察结果:
import numpy as np
import timeit
a = np.random.randint(0, 5, 100000)
b = np.random.randint(0, 5, 100000)
c = np.random.randint(0, 5, 100000)
method_one = np.logical_and(np.logical_and(a, b), c)
%timeit np.logical_and(np.logical_and(a, b), c)
method_two = a*b*c != 0
%timeit a*b*c != 0
method_three = np.logical_and(np.logical_and(a.astype('bool'), b.astype('bool')), c.astype('bool'))
%timeit np.logical_and(np.logical_and(a.astype('bool'), b.astype('bool')), c.astype('bool'))
method_four = a.astype('bool') * b.astype('bool') * c.astype('bool') != 0
%timeit a.astype('bool') * b.astype('bool') * c.astype('bool') != 0
# verify all methods give equivalent results
all([
np.all(method_one == method_two),
np.all(method_one == method_three),
np.all(method_one == method_four)
]
)
1000 loops, best of 3: 713 µs per loop
1000 loops, best of 3: 341 µs per loop
1000 loops, best of 3: 252 µs per loop
1000 loops, best of 3: 388 µs per loop
True
一些解释:
a*b*c != 0
方法的速度取决于向量的dtype
,因为乘法是先完成的。因此,如果您有浮点数或bigints或其他更大的dtype,则此步骤将比具有布尔值或小整数的相同长度的向量花费更长的时间。强制转换为bool
dtype
会加快此方法的速度。如果向量具有不同的 dtypes,则事情会更慢。将整数数组乘以浮点数组需要将整数转换为浮点数,然后转换为布尔值。不是最佳的。
由于我不明白的原因, Prune 的答复声明
但是,逻辑测试更快似乎只有在输入向量已经是布尔值时才是正确的。也许在直接logical_and()
方法中强制转换为布尔值的方式比使用.asdtype('bool')
要慢。
最快的方法似乎是(1)提前强制输入布尔值,然后(2)使用np.logical_and()
。
答案 2 :(得分:0)
给出简短摘要:a * b * c != 0
可能导致上溢或下溢。替代~((a == 0) | (b == 0) | (c == 0))
似乎比任何其他测试实现执行得更快。
答案 3 :(得分:-1)
他们是一样的。 0和无错误;任何其他值 True 。但是,逻辑测试更快。如果列表中有很多数组,请考虑使用Python的所有和任何方法。
例如:
for value in [True, False, 0, 1, None, 7, 'a', [False, False, False]]:
if value:
print value, True
else:
print value, False
输出:
True True
False False
0 False
1 True
None False
7 True
a True
[False, False, False] True