获取布尔数组中至少 n 个连续 False 值的第一个块的索引
get index of the first block of at least n consecutive False values in boolean array
我有一个 numpy
布尔数组
w=np.array([True,False,True,True,False,False,False])
我想获取第一个在 n_at_least
处有错误值的索引。
比如这里
`n_at_least`=1 -> desired_index=1
`n_at_least`=3 -> desired_index=4
我试过了
np.cumsum(~w)
每次遇到 False
值时都会增加。
但是,当遇到 True
时,计数器不再从 0 开始,所以我只得到 False
元素的总数,而不是最后一个连续元素的计数。
它应该这样工作:
def n_at_least(n):
for i in range(len(w)):
if not any(w[i:i+n]):
return i
不过不知道有没有更好的办法...
我认为您陷入了只想使用 numpy 函数的 numpy 陷阱。 python 怎么了?这个解决方案是O(n)
def f(array, n_at_least):
curr_found_false = 0
curr_index = 0
for index, elem in enumerate(array):
if not elem:
if curr_found_false == 0:
curr_index = index
curr_found_false += 1
if curr_found_false == n_at_least:
return curr_index
else:
curr_found_false = 0
产出
w=np.array([True,False,True,True,False,False,False])
f(w, 1)
# --> 1
f(w, 3)
# --> 4
这是一个向量化的解决方案,可以找到起始索引、终止索引以及 岛屿 的零长度,最后使用 argmax
获取第一个岛屿的起始索引满足零计数的标准是 >= n
-
def first_occ_index(w, n):
idx = np.flatnonzero(np.r_[True, w, True])
lens = np.diff(idx) - 1
return idx[(lens >= n).argmax()]
样本运行-
In [107]: w
Out[107]: array([ True, False, True, True, False, False, False])
In [108]: first_occ_index(w, n=1)
Out[108]: 1
In [109]: first_occ_index(w, n=3)
Out[109]: 4
这是一个复杂度为 O(n) 的 numpy 解决方案:
>>> def first_consec(A, n):
... A = np.r_[True, A, True]
... switch, = np.where(A[:-1]!=A[1:])
... runs = switch[1::2] - switch[::2]
... idx = np.argmax(runs >= n)
... if runs[idx] < n:
... return None
... return switch[2*idx]
...
>>> first_consec(w, 4)
>>> first_consec(w, 3)
4
>>> first_consec(w, 2)
4
>>> first_consec(w, 1)
1
这是使用带切片的生成器表达式的一种方法:
w = np.array([True,False,True,True,False,False,False])
n = 2
val = False
res = next((i for i, j in enumerate(w[k:k+n] for k in range(len(w)-n+1)) \
if np.all(j==val)), None)
# 4
我认为对于这种线性搜索操作,python 实现是可以的。我的建议是这样的:
def find_block(arr, n_at_least=1):
current_index = 0
current_count = 0
for index, item in enumerate(arr):
if item:
current_count = 0
current_index = index + 1
else:
current_count += 1
if current_count == n_at_least:
return current_index
return None # Make sure this is outside for loop
运行 此函数产生以下输出:
>>> import numpy
>>> w = numpy.array([True, False, True, True, False, False, False])
>>> find_block(w, n_at_least=1)
1
>>> find_block(w, n_at_least=3)
4
>>> find_block(w, n_at_least=4)
>>> # None
我有一个 numpy
布尔数组
w=np.array([True,False,True,True,False,False,False])
我想获取第一个在 n_at_least
处有错误值的索引。
比如这里
`n_at_least`=1 -> desired_index=1
`n_at_least`=3 -> desired_index=4
我试过了
np.cumsum(~w)
每次遇到 False
值时都会增加。
但是,当遇到 True
时,计数器不再从 0 开始,所以我只得到 False
元素的总数,而不是最后一个连续元素的计数。
它应该这样工作:
def n_at_least(n):
for i in range(len(w)):
if not any(w[i:i+n]):
return i
不过不知道有没有更好的办法...
我认为您陷入了只想使用 numpy 函数的 numpy 陷阱。 python 怎么了?这个解决方案是O(n)
def f(array, n_at_least):
curr_found_false = 0
curr_index = 0
for index, elem in enumerate(array):
if not elem:
if curr_found_false == 0:
curr_index = index
curr_found_false += 1
if curr_found_false == n_at_least:
return curr_index
else:
curr_found_false = 0
产出
w=np.array([True,False,True,True,False,False,False])
f(w, 1)
# --> 1
f(w, 3)
# --> 4
这是一个向量化的解决方案,可以找到起始索引、终止索引以及 岛屿 的零长度,最后使用 argmax
获取第一个岛屿的起始索引满足零计数的标准是 >= n
-
def first_occ_index(w, n):
idx = np.flatnonzero(np.r_[True, w, True])
lens = np.diff(idx) - 1
return idx[(lens >= n).argmax()]
样本运行-
In [107]: w
Out[107]: array([ True, False, True, True, False, False, False])
In [108]: first_occ_index(w, n=1)
Out[108]: 1
In [109]: first_occ_index(w, n=3)
Out[109]: 4
这是一个复杂度为 O(n) 的 numpy 解决方案:
>>> def first_consec(A, n):
... A = np.r_[True, A, True]
... switch, = np.where(A[:-1]!=A[1:])
... runs = switch[1::2] - switch[::2]
... idx = np.argmax(runs >= n)
... if runs[idx] < n:
... return None
... return switch[2*idx]
...
>>> first_consec(w, 4)
>>> first_consec(w, 3)
4
>>> first_consec(w, 2)
4
>>> first_consec(w, 1)
1
这是使用带切片的生成器表达式的一种方法:
w = np.array([True,False,True,True,False,False,False])
n = 2
val = False
res = next((i for i, j in enumerate(w[k:k+n] for k in range(len(w)-n+1)) \
if np.all(j==val)), None)
# 4
我认为对于这种线性搜索操作,python 实现是可以的。我的建议是这样的:
def find_block(arr, n_at_least=1):
current_index = 0
current_count = 0
for index, item in enumerate(arr):
if item:
current_count = 0
current_index = index + 1
else:
current_count += 1
if current_count == n_at_least:
return current_index
return None # Make sure this is outside for loop
运行 此函数产生以下输出:
>>> import numpy
>>> w = numpy.array([True, False, True, True, False, False, False])
>>> find_block(w, n_at_least=1)
1
>>> find_block(w, n_at_least=3)
4
>>> find_block(w, n_at_least=4)
>>> # None