假设我有一个这样的数组:
numpy.array([0, 0, 1, 2, 3, 0, 0, 4, 5, 0, 0, 0, 0, 1, 0, 6, 0, 7, 8, 9, 0, 0, 0, 8, 10, 0])
字符串
定义一个长度(N)和一个值(K),我想确定一系列的值(包括零),这些值被彼此除以至少N个连续的K,每个块的开始和停止索引。
因此,与:
N = 2
K = 0
型
我们最终将得到:
#blocks
[ [1, 2, 3], [4, 5], [1, 0, 6, 0, 7, 8, 9], [8, 10] ]
#indexes
[ [2, 4], [7, 8], [13, 19], [23, 24] ]
的字符串
在该示例中,块3(索引为2)还包含0,即所选择的K值,因为没有足够的连续出现(至少N个)来标识两个独立块。
实现这种避免循环的最聪明的方法是什么?
现在我采用了这种方法:
def consecutive_blocks(arr,K,N):
d = numpy.diff(numpy.concatenate(([False], arr==K, [False])).astype(int))
idx_i = numpy.flatnonzero(d == -1)[:-1]
idx_j = numpy.flatnonzero(d == 1)[1:] - 1
delta = numpy.flatnonzero(d == -1) - numpy.flatnonzero(d == 1)
idx_ii = idx_i[numpy.where(delta >= N)[0]]
return idx_ii
型
这样我就得到了块的起始索引,但是我还需要进一步的工作来得到结束索引。
1条答案
按热度按时间mwg9r5ms1#
这里有一个方法:
字符串
b
创建一个2D矩阵,其中每行对应于长度为N的值的滚动子范围。c
查找与K重复N次模式匹配的行的索引。这给出了[0,0]子范围的起始位置。添加表示数组开始和结束的索引以完成边缘范围。d
将每个起始位置与下一个起始位置组合以形成索引范围。开始索引增加N以获得第一个非K值,并且接下来的开始减少1以获得组中最后一个项目的索引。e
消除了由多于N个连续K值的序列引起的“空”范围。根据下面的注解,可以通过更改前两行来利用
as_strided
或sliding_window_view
(* 我只能测试as_strided
*)来获得更好的性能:型
中间值:
型
...
型
...
型