Python 数组的最长前缀等于一个值

Python 数组的最长前缀等于一个值,python,numpy,Python,Numpy,我有表示序列分段的字符串的NumPy数组B是感兴趣的段的开始,I它的延续,O在任何段之外。例如,在以下数组中,有三个感兴趣的段: >>> y array(['B', 'I', 'I', 'O', 'B', 'I', 'O', 'O', 'B', 'O'], dtype='|S1') 我可以很容易地找到以np开头的片段。其中(y==“B”)[0]。但现在我还试图找到段的长度,即最长前缀的长度等于I。我可以使用itertools执行此操作。takewhile: &g

我有表示序列分段的字符串的NumPy数组
B
是感兴趣的段的开始,
I
它的延续,
O
在任何段之外。例如,在以下数组中,有三个感兴趣的段:

>>> y
array(['B', 'I', 'I', 'O', 'B', 'I', 'O', 'O', 'B', 'O'], 
      dtype='|S1')
我可以很容易地找到以
np开头的片段。其中(y==“B”)[0]
。但现在我还试图找到段的长度,即最长前缀的长度等于
I
。我可以使用
itertools执行此操作。takewhile

>>> from itertools import takewhile
>>> lengths = [1 + sum(1 for _ in takewhile(lambda x: x == "I", y[start + 1:]))
...            for start in np.where(y == "B")[0]]
>>> lengths
[3, 2, 1]

老实说,这很好,但是有没有一种矢量化的方法来实现这一点?

搜索排序可以帮助您:

>>> y
array(['B', 'I', 'I', 'O', 'B', 'I', 'O', 'O', 'B', 'O'],
      dtype='|S1')
>>> start=np.where(y=='B')[0]
>>> end=np.where(y=='O')[0]

>>> end[np.searchsorted(end,start)]-start
array([3, 2, 1])
另一种方法:

>>> mask=np.concatenate(([True],(np.diff(end)!=1)))
>>> mask
array([ True,  True, False,  True], dtype=bool)
>>> end[mask]-start
array([3, 2, 1])

段以A
'B'
开头:

starts = np.where(y == 'B')[0]
'B'
'I'
后面跟有
'I'
以外的内容时,段结束,或在序列的末尾:

ends = np.where(((y == 'B') | (y == 'I')) & np.r_[y[1:] != 'I', len(y)])[0]
这将给出段长度:

(ends - starts) + 1
array([3, 2, 1])

编辑:这里有一个更简单的方法:在末尾插入一个虚构的
B
,然后取(真实的或虚构的)
B
s的位置差,不包括
O
s:

np.diff(np.where(np.r_[y[y != 'O'], ['B']] == 'B')[0])
array([3, 2, 1])

出于好奇,有没有列出所有numpy方法在某个地方的规模。大多数只是线性时间,但搜索和排序显然不能。