2016-04-09 28 views
-2

でシーケンスを検索するのは、私は次の配列を持っているとしましょう:[0,0]numpyの配列

array([2, 0, 0, 1, 0, 1, 0, 0]) 

は、どのように私は、値のシーケンスの発生を持っている指標を得るのですか?したがって、そのような場合の予想出力は[1,2,6,7]となります。

編集:

1)[0,0]がちょうどシーケンスであることに注意してください。 [0,0,0]または[4,6,8,9]または[5,2,0]のいずれかです。

2)私の配列がarray([2, 0, 0, 0, 0, 1, 0, 1, 0, 0])に変更された場合、同じ配列[0,0]で期待される結果は[1,2,3,4,8,9]となります。

私はいくつかのNumPyショートカットを探しています。ここで

+4

'array([2、0、0,0、1,0,0,0,0)]'とはどういう意味ですか? –

+1

私はあなたの質問を正しく理解していれば、[0、0]を例にして、任意のシーケンスに対応できる汎用メソッドが必要ですか? – Reti43

答えて

5

あなたの要件を満たす必要がありますまあ、これは基本的にあると思いますtemplate-matching problemが画像処理に多く含まれています。この記事には、純粋なNumPyベースとOpenCV(cv2)ベースの2つのアプローチが掲​​載されています。

アプローチ#1: NumPyを使用すると、入力配列の全長にわたって滑り指標の配列2Dを作成できます。したがって、各行は要素のスライディングウィンドウになります。次に、各行を入力シーケンスに一致させ、ベクトル化された解をbroadcastingにします。すべてのTrue行を探します。これらの行は完全一致であり、一致の開始インデックスとなることを示しています。最後に、これらのインデックスを使用して、シーケンスの長さまで伸びるインデックスの範囲を作成し、目的の出力を与えます。実装は次のようになります -

def search_sequence_numpy(arr,seq): 
    """ Find sequence in an array using NumPy only. 

    Parameters 
    ----------  
    arr : input 1D array 
    seq : input 1D array 

    Output 
    ------  
    Output : 1D Array of indices in the input array that satisfy the 
    matching of input sequence in the input array. 
    In case of no match, empty list is returned. 
    """ 

    # Store sizes of input array and sequence 
    Na, Nseq = arr.size, seq.size 

    # Range of sequence 
    r_seq = np.arange(Nseq) 

    # Create 2D array of sliding indices across entire length of input array. 
    # Match up with the input sequence & get the matching starting indices. 
    M = (arr[np.arange(Na-Nseq+1)[:,None] + r_seq] == seq).all(1) 

    # Get the range of those indices as final output 
    if M.any>0: 
     return np.where(np.convolve(M,np.ones((Nseq),dtype=int))>0)[0] 
    else: 
     return []   # No match found 

アプローチ#2:cv2.matchTemplate:OpenCVの(CV2)で、我々はtemplate-matchingのための組み込み関数を持っています。これを使用して、最初に一致するインデックスがあります。ステップの残りの部分は、以前のアプローチと同じです。

from cv2 import matchTemplate as cv2m 

def search_sequence_cv2(arr,seq): 
    """ Find sequence in an array using cv2. 
    """ 

    # Run a template match with input sequence as the template across 
    # the entire length of input array and get scores. 
    S = cv2m(arr.astype('uint8'),seq.astype('uint8'),cv2.TM_SQDIFF) 

    # Now, with floating point array cases, the matching scores might not be 
    # exactly zeros, but would be very small numbers as compared to others. 
    # So, for that use a very small to be used to threshold the scorees 
    # against and decide for matches. 
    thresh = 1e-5 # Would depend on elements in seq. So, be careful setting this. 

    # Find the matching indices 
    idx = np.where(S.ravel() < thresh)[0] 

    # Get the range of those indices as final output 
    if len(idx)>0: 
     return np.unique((idx[:,None] + np.arange(seq.size)).ravel()) 
    else: 
     return []   # No match found 

サンプル実行

In [512]: arr = np.array([2, 0, 0, 0, 0, 1, 0, 1, 0, 0]) 

In [513]: seq = np.array([0,0]) 

In [514]: search_sequence_numpy(arr,seq) 
Out[514]: array([1, 2, 3, 4, 8, 9]) 

In [515]: search_sequence_cv2(arr,seq) 
Out[515]: array([1, 2, 3, 4, 8, 9]) 

ランタイムテスト

In [477]: arr = np.random.randint(0,9,(100000)) 
    ...: seq = np.array([3,6,8,4]) 
    ...: 

In [478]: np.allclose(search_sequence_numpy(arr,seq),search_sequence_cv2(arr,seq)) 
Out[478]: True 

In [479]: %timeit search_sequence_numpy(arr,seq) 
100 loops, best of 3: 11.8 ms per loop 

In [480]: %timeit search_sequence_cv2(arr,seq) 
10 loops, best of 3: 20.6 ms per loop 

ピュアnumpyのベースの一つであり、最も安全とfastesように思える:ここcv2と実装がありますt!

0

がforloop

def find_seq(a_list, val): 

    seqs = [] 
    for i, item in enumerate(a_list[:-1]): 
     if item == val and a_list[i + 1] == val: 
      #or you could append a tuple: seqs.append((i, i+1)) 
      seqs.append(i) 
      seqs.append(i + 1) 
    return seqs 

print(find_seq([2, 0, 0, 1, 0, 1, 0, 0], 0)) 

結果でそれを行うための一つの方法です:

[1, 2, 6, 7] 
0

私は、これは

def search(seq, lst): 
    ls, ll = len(seq), len(lst) 
    r = range(ls) 
    res = [] 
    i = 0 
    while i<ll-ls: 
     if lst[i:i+ls]!=seq: 
      i = i+1 
     else: 
      res = res + [i+j for j in r] # concatenate list of indices and new indices 
      i = i+ls      # advance index after the match 
    return res