3

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

>>> y
array(['B', 'I', 'I', 'O', 'B', 'I', 'O', 'O', 'B', 'O'], 
      dtype='|S1')

我可以发现这些段很容易以np.where(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]

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

4

2 回答 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])
于 2013-07-29T16:57:47.603 回答
1

一个段以 a 开头'B'

starts = np.where(y == 'B')[0]

段结束于 a 'B'or'I'后跟除 a 以外的其他内容'I',或在序列结尾处:

ends = np.where(((y == 'B') | (y == 'I')) & np.r_[y[1:] != 'I', len(y)])[0]

这给出了段长度:

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

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

np.diff(np.where(np.r_[y[y != 'O'], ['B']] == 'B')[0])
array([3, 2, 1])
于 2013-07-29T17:03:47.987 回答