あなたの要件を満たす必要がありますまあ、これは基本的にあると思います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!
'array([2、0、0,0、1,0,0,0,0)]'とはどういう意味ですか? –
私はあなたの質問を正しく理解していれば、[0、0]を例にして、任意のシーケンスに対応できる汎用メソッドが必要ですか? – Reti43