簡體   English   中英

如何判斷numpy布爾數組是否只包含一個“True`s”塊?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM