4

想象一下,我有一个 numpy 数组,我需要找到条件为真的跨度/范围。例如,我有以下数组,我试图在其中查找项目大于 1 的跨度:

[0, 0, 0, 2, 2, 0, 2, 2, 2, 0]

我需要找到索引(开始,停止):

(3, 5) 
(6, 9)

我能够实现的最快的事情是制作一个布尔数组:

truth = data > threshold

然后使用numpy.argminand循环遍历数组numpy.argmax以查找开始和结束位置。

    pos = 0
    truth = container[RATIO,:] > threshold

    while pos < len(truth):
        start = numpy.argmax(truth[pos:]) + pos + offset
        end = numpy.argmin(truth[start:]) + start  + offset
        if not truth[start]:#nothing more
            break
        if start == end:#goes to the end
            end = len(truth)
        pos = end

但这对于我的数组中的数十亿个位置来说太慢了,而且我发现的跨度通常只是连续的几个位置。有谁知道找到这些跨度的更快方法?

4

2 回答 2

5

一种方式如何。首先获取您拥有的布尔数组:

In [11]: a
Out[11]: array([0, 0, 0, 2, 2, 0, 2, 2, 2, 0])

In [12]: a1 = a > 1

使用以下命令将其向左移动一个(以获取每个索引处的下一个状态)roll

In [13]: a1_rshifted = np.roll(a1, 1)

In [14]: starts = a1 & ~a1_rshifted  # it's True but the previous isn't

In [15]: ends = ~a1 & a1_rshifted

非零是每个 True 批次开始(或分别为结束批次):

In [16]: np.nonzero(starts)[0], np.nonzero(ends)[0]
Out[16]: (array([3, 6]), array([5, 9]))

并将它们压缩在一起:

In [17]: zip(np.nonzero(starts)[0], np.nonzero(ends)[0])
Out[17]: [(3, 5), (6, 9)]
于 2013-06-17T15:32:06.343 回答
2

如果您有权访问 scipy 库:

您可以使用scipy.ndimage.measurements.label来识别任何非零值区域。它返回一个数组,其中每个元素的值是原始数组中跨度或范围的 id。

然后,您可以使用scipy.ndimage.measurements.find_objects返回提取这些范围所需的切片。您可以直接从这些切片访问开始/结束值。

在您的示例中:

import numpy
from scipy.ndimage.measurements import label, find_objects

data = numpy.array([0, 0, 0, 2, 2, 0, 2, 2, 2, 0])

labels, number_of_regions = label(data)
ranges = find_objects(labels)

for identified_range in ranges:
    print(identified_range[0].start, identified_range[0].stop)

你应该看到:

3 5
6 9

希望这可以帮助!

于 2013-12-06T11:56:28.170 回答