[英]How can I tell whether a numpy boolean array contains only a single block of `True`s?
如果我有一個包含布爾值的numpy數組,比如一些數學比較的輸出,那么確定該數組是否只包含一個連續的True
塊的最佳方法是什么,例如
array([False, False, False, True, True, True, False, False, False], dtype=bool)
即序列...,True, False, ..., True...
永遠不會發生?
numpy.diff
在這種情況下很有用。 您可以計算diff
數組中-1的數量。
注意,你還需要檢查最后一個元素 - 如果它是True,則diff
數組中不會有-1表示這一點。 更好的是,您可以在diff
之前將False
附加到數組。
import numpy as np
a = np.array([False, False, False, True, True, True, False, False, False], dtype=bool)
d = np.diff(np.asarray(a, dtype=int))
d
=> array([ 0, 0, 1, 0, 0, -1, 0, 0])
(d < 0).sum()
=> 1
要在末尾添加False
:
b = np.append(a, [ False ])
d = np.diff(np.asarray(b, dtype=int))
...
現在,“序列......,真,假,......,真......永遠不會發生”iff (d<0).sum() < 2
。
避免append
操作(並使代碼更加模糊)的一個技巧是: (d<0).sum() + a[-1] < 2
(即,如果[-1]為真,則計算它作為一個塊)。 當然,這只有在a不為空的情況下才有效。
不是numpy
本地方法,但你可以使用itertools.groupby
減少連續值的塊成一個單一的項目,然后檢查,只有truthy值出現一次使用any
。 由於grouped
是可迭代的,所以只要找到True
值,第一個any
返回True
,然后你繼續檢查迭代的剩余部分,並確保沒有另一個真值。
from itertools import groupby
def has_single_true_block(sequence):
grouped = (k for k, g in groupby(sequence))
has_true = any(grouped)
has_another_true = any(grouped)
return has_true and not has_another_true
如果你只有一個Trues塊,那意味着你要么在數組中有一個轉換,要么你有兩個轉換,數組以False開始和結束。 還有一個簡單的例子,整個數組都是True。 所以你可以這樣做:
def singleBlockTrue(array):
if len(array) == 0:
return False
transitions = (array[1:] != array[:-1]).sum()
if transitions == 0:
return array[0]
if transitions == 1:
return True
if transitions == 2:
return not array[0]
return False
這實際上是相同的邏輯,但代碼更清潔。
def singleBlockTrue(array):
if len(array) == 0:
return False
transitions = (array[1:] != array[:-1]).sum()
transitions = transitions + array[0] + array[-1]
return transitions == 2
一些與評論相關的時間:
In [41]: a = np.zeros(1000000, dtype=bool)
In [42]: timeit a[:-1] != a[1:]
100 loops, best of 3: 2.93 ms per loop
In [43]: timeit np.diff(a.view('uint8'))
100 loops, best of 3: 2.45 ms per loop
In [44]: timeit np.diff(a.astype('uint8'))
100 loops, best of 3: 3.41 ms per loop
In [45]: timeit np.diff(np.array(a, 'uint8'))
100 loops, best of 3: 3.42 ms per loop
import numpy as np
def has_single_true_block(arr):
if not len(arr):
return False
blocks = len(np.array_split(arr, np.where(np.diff(arr) != 0)[0] + 1))
if blocks > 3:
return False
elif blocks == 3 and arr[0] and arr[-1]:
return False
elif blocks == 1 and not arr[0]: # 0 True blocks
return False
return True
# TESTS
a1 = np.array([False, False, True, True, True, False, False], dtype=bool)
has_single_true_block(a1) # => True
a2 = np.array([True, True, False, False], dtype=bool)
has_single_true_block(a2) # => True
a3 = np.array([False, False, True, True], dtype=bool)
has_single_true_block(a3) # => True
f1 = np.array([False, False, True, False, True, False, False], dtype=bool)
has_single_true_block(f1) # => False
f2 = np.array([True, True, False, False, True, True], dtype=bool)
has_single_true_block(f2) # => False
f3 = np.array([False, False, False], dtype=bool)
has_single_true_block(f3) # => False
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.