Nun erfüllen sollte, ist dies im Grunde ein template-matching problem
das kommt in der Bildverarbeitung sehr oft vor. In diesem Beitrag sind zwei Ansätze aufgeführt: Pure NumPy basiert und OpenCV (cv2) basiert.
Ansatz # 1: Mit NumPy kann man ein 2D
Array gleitender Indizes über die gesamte Länge des Eingangsarrays erstellen. Somit wäre jede Reihe ein gleitendes Fenster von Elementen. Ordnen Sie als nächstes jede Zeile der Eingabesequenz zu, die broadcasting
für eine vektorisierte Lösung enthält. Wir suchen nach allen True
Zeilen, die anzeigen, dass diejenigen diejenigen sind, die die perfekten Übereinstimmungen sind, und als solche wären die Startindizes der Spiele. Unter Verwendung dieser Indizes erstellen Sie schließlich eine Reihe von Indizes, die sich bis zur Länge der Sequenz erstrecken, um die gewünschte Ausgabe zu erhalten. Die Umsetzung wäre -
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
Ansatz # 2: Mit OpenCV (cv2), haben wir eine integrierte Funktion für template-matching
: cv2.matchTemplate
. Damit hätten wir die passenden Startindizes. Der Rest der Schritte wäre der gleiche wie für den vorherigen Ansatz. Hier ist die Umsetzung mit cv2
:
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
Probelauf
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])
Runtime Test
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
scheint, wie die reine NumPy Basis ist die sicherste und schnellste t!
Was ist mit 'Array ([2, 0, 0,0, 1, 0, 1, 0, 0])'? –
Wenn ich Ihre Frage richtig verstanden habe, möchten Sie eine generische Methode, die für jede Sequenz geeignet ist, wobei [0, 0] nur ein Beispiel ist? – Reti43