4

numpy 配列があり、その条件が True であるスパン/範囲を見つける必要があるとします。たとえば、項目が 1 より大きいスパンを見つけようとしている次の配列があります。

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

インデックス (開始、停止) を見つける必要があります。

(3, 5) 
(6, 9)

私が実装できた最速の方法は、次のブール配列を作成することです。

truth = data > threshold

numpy.argmin次に、 andを使用して配列をループし、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

次を使用して、左に 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 に答える