gegeben ein Array von ganzen Zahlen wie
[1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5]
Ich muss Elemente maskieren, die sich N
mehrmals wiederholen . Zur Verdeutlichung: Das Hauptziel besteht darin, das boolesche Maskenarray abzurufen und später für Binning-Berechnungen zu verwenden.
Ich habe eine ziemlich komplizierte Lösung gefunden
import numpy as np
bins = np.array([1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5])
N = 3
splits = np.split(bins, np.where(np.diff(bins) != 0)[0]+1)
mask = []
for s in splits:
if s.shape[0] <= N:
mask.append(np.ones(s.shape[0]).astype(np.bool_))
else:
mask.append(np.append(np.ones(N), np.zeros(s.shape[0]-N)).astype(np.bool_))
mask = np.concatenate(mask)
zB geben
bins[mask]
Out[90]: array([1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5])
Gibt es einen schöneren Weg, dies zu tun?
EDIT, # 2
Vielen Dank für die Antworten! Hier ist eine schlanke Version von MSeiferts Benchmark-Plot. Danke, dass du mich darauf hingewiesen hast simple_benchmark
. Zeigt nur die 4 schnellsten Optionen an:
Fazit
Die von Florian H vorgeschlagene , von Paul Panzer modifizierte Idee scheint eine großartige Möglichkeit zu sein, dieses Problem zu lösen, da sie ziemlich einfach und numpy
nur ist. Wenn Sie numba
jedoch gut damit umgehen können , übertrifft die Lösung von MSeifert die andere.
Ich habe mich entschieden, die Antwort von MSeifert als Lösung zu akzeptieren, da dies die allgemeinere Antwort ist: Sie behandelt beliebige Arrays mit (nicht eindeutigen) Blöcken aufeinanderfolgender sich wiederholender Elemente korrekt. Falls numba
es ein No-Go ist, ist Divakars Antwort auch einen Blick wert!
Antworten:
Ich möchte eine Lösung mit numba vorstellen, die ziemlich einfach zu verstehen sein sollte. Ich gehe davon aus, dass Sie aufeinanderfolgende sich wiederholende Elemente "maskieren" möchten:
Zum Beispiel:
Performance:
Verwenden
simple_benchmark
- allerdings habe ich nicht alle Ansätze berücksichtigt. Es ist eine Log-Log-Skala:Es scheint, dass die Numba-Lösung die Lösung von Paul Panzer nicht übertreffen kann, die für große Arrays etwas schneller zu sein scheint (und keine zusätzliche Abhängigkeit erfordert).
Beide scheinen jedoch die anderen Lösungen zu übertreffen, geben jedoch anstelle des "gefilterten" Arrays eine Maske zurück.
quelle
out
Argument (oder vielleicht die funktionale Form des Operators) nicht, daher konnte ich diese Kopie nicht speichern. Übrigens mag ich ganzsimple_benchmark
.simple_benchmark
! danke dafür und danke natürlich für die antwort. Da ich auchnumba
für andere Dinge verwende, neige ich dazu, es auch hier zu verwenden und dies zur Lösung zu machen. zwischen einem Felsen und einem harten Ort dort ...Haftungsausschluss: Dies ist nur eine fundiertere Umsetzung der Idee von @ FlorianH:
Bei größeren Arrays macht dies einen großen Unterschied:
quelle
[1,1,1,1,2,2,1,1,2,2]
.Ansatz 1: Hier ist ein vektorisierter Weg -
Probelauf -
Ansatz 2: Eine etwas kompaktere Version -
Ansatz 3: Verwenden der gruppierten Zählungen und
np.repeat
(gibt uns jedoch keine Maske) -Ansatz 4: Mit einer
view-based
Methode -Ansatz 5: Mit einer
view-based
Methode ohne Indizes vonflatnonzero
-quelle
Sie können dies mit der Indizierung tun. Für jedes N wäre der Code:
Ausgabe:
quelle
timeit
Läufen nachsehen.Ein viel schönerer Weg wäre, die Funktion von
numpy
's zu verwendenunique()
. Sie erhalten eindeutige Einträge in Ihrem Array und die Anzahl, wie oft sie angezeigt werden:Ausgabe:
quelle
Sie können eine while-Schleife verwenden, die prüft, ob die Position N des Array-Elements N gleich der aktuellen ist. Beachten Sie, dass diese Lösung davon ausgeht, dass das Array geordnet ist.
quelle
len(question)
zulen(bins)
Sie können grouby verwenden , um allgemeine Elemente und Filterlisten zu gruppieren, die länger als N sind .
quelle
Lösung
Sie könnten verwenden
numpy.unique
. Die Variablefinal_mask
kann verwendet werden, um die Traget-Elemente aus dem Array zu extrahierenbins
.Ausgabe :
quelle
bins
, oder?final_values
direkt, könnten Sie Kommentar- die einzigen kommentierte Linie in der Lösung und in diesem Fall könnten Sie drei Zeilen verwerfen:mask = ...
,final_mask = ...
undbins[final_mask]
.