找出列表中的所有非0区间
1. 题目描述
这个题目其实是我自己定义出来的,然后再Stack Overflow上看到一个很巧妙的解决思路,在这里记一下。
大概是这样,在视频异常检测的任务中,你大概率会遇到这样的场景,比如一个视频中,有中间的某些段落是异常的(标记为1),而剩下的是正常的(标记为0)。现在我们需要把那些异常的段的起始帧和结束帧位置找到,也就是在[0...0,1...1,0...0,1...1,0...0]
中去找到所有非0的区间。当然,找为0的区间是一样的问题了。
2. 思路
要说这个嘛,也倒不是很难,大不了遍历一遍,然后每当遇到0/1翻转,就记录一下那个索引,一直找到所有的索引,然后再切成一段一段的区间。问题就出在怎么切成一段一段的时候,虽然说,一般来说,一个异常的区间都应该是多帧的,但也万一说不准刚好某个区间只包含一帧的情况,就会在遍历的时候不好处理。直到我看到了Stack Overflow上一个巧妙的代码。
Python 实现1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25import numpy as np:
def nonzero_intervals(vec):
'''
Find islands of non-zeros in the vector vec
'''
if len(vec) == 0:
return []
elif not isinstance(vec, np.ndarray):
vec = np.array(vec)
tmp = (vec == 0) * 1
tmp = np.diff(tmp) # 找到所有的0/1和1/0翻转处
edges, = np.nonzero(tmp) # 记录所有翻转处的坐标
edge_vec = [edges + 1]
# 处理开头和结尾刚好是非0的情况
if vec[0] != 0:
edge_vec.insert(0, [0])
if vec[-1] != 0:
edge_vec.append([len(vec)])
edges = np.concatenate(edge_vec)
# 返回一个iterable对象
return zip(edges[::2], edges[1::2])