Ich muss eindeutige Zeilen in a finden numpy.array
.
Beispielsweise:
>>> a # I have
array([[1, 1, 1, 0, 0, 0],
[0, 1, 1, 1, 0, 0],
[0, 1, 1, 1, 0, 0],
[1, 1, 1, 0, 0, 0],
[1, 1, 1, 1, 1, 0]])
>>> new_a # I want to get to
array([[1, 1, 1, 0, 0, 0],
[0, 1, 1, 1, 0, 0],
[1, 1, 1, 1, 1, 0]])
Ich weiß, dass ich ein Set und eine Schleife über das Array erstellen kann, aber ich suche nach einer effizienten reinen numpy
Lösung. Ich glaube, dass es eine Möglichkeit gibt, den Datentyp auf void zu setzen, und dann könnte ich ihn einfach verwenden numpy.unique
, aber ich konnte nicht herausfinden, wie er funktioniert.
Antworten:
Ab NumPy 1.13 kann einfach die Achse für die Auswahl eindeutiger Werte in einem beliebigen N-Dim-Array ausgewählt werden. Um eindeutige Zeilen zu erhalten, kann man Folgendes tun:
unique_rows = np.unique(original_array, axis=0)
quelle
np.unique(list_cor, axis=0)
Sie erhalten das Array mit entfernten doppelten Zeilen . Das Array wird nicht nach Elementen gefiltert, die im ursprünglichen Array eindeutig sind . Siehe hier zum Beispiel ..original_array.sort(axis=1)
Noch eine mögliche Lösung
quelle
np.vstack(list({tuple(row) for row in AIPbiased[i, :, :]}))
FutureWarning: Arrays zum Stapeln müssen als "Sequenz" -Typ wie Liste oder Tupel übergeben werden. Die Unterstützung für nicht sequenzierte Iterables wie Generatoren ist ab NumPy 1.16 veraltet und wird in Zukunft einen Fehler auslösen.Eine weitere Option für die Verwendung strukturierter Arrays ist die Verwendung einer Ansicht eines
void
Typs, der die gesamte Zeile zu einem einzigen Element zusammenfügt:EDIT hinzugefügt
np.ascontiguousarray
folgende @ seberg Empfehlung. Dies verlangsamt die Methode, wenn das Array noch nicht zusammenhängend ist.BEARBEITEN Das oben Genannte kann leicht beschleunigt werden, möglicherweise auf Kosten der Klarheit, indem Sie Folgendes tun:
Zumindest auf meinem System ist es in Bezug auf die Leistung gleich oder sogar besser als die Lexsort-Methode:
quelle
b = a.view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))
?np.void
Datentyp erstellt, der der Anzahl der Bytes in einer vollständigen Zeile entspricht. Es sind zwei ähnliche, die Sie erhalten, wenn Sie ein Array vonnp.uint8
s haben und es alsnp.uint16
s anzeigen , das alle zwei Spalten zu einer einzigen kombiniert, aber flexibler ist.np.ascontiguousarray
oder ähnliches hinzufügen , um allgemein sicher zu sein (ich weiß, es ist etwas restriktiver als nötig, aber ...). Die Zeilen müssen zusammenhängend sein, damit die Ansicht wie erwartet funktioniert.np.unique
auf einem Array von ausgeführt zu werden,np.void
ein Fehler zurückgegeben, der darauf zurückzuführen ist, dass Mergesort für diesen Typ nicht implementiert wurde. In 1.7 funktioniert es jedoch einwandfrei.-0.
der nicht gleich ist+0.
, wohingegen ein Element-für-Element-Vergleich dies hätte-0.==+0.
(wie im ieee-Gleitkomma-Standard angegeben). Siehe stackoverflow.com/questions/26782038/…Wenn Sie die Speicherkosten für die Konvertierung in eine Reihe von Tupeln oder eine andere ähnliche Datenstruktur vermeiden möchten, können Sie die strukturierten Arrays von numpy nutzen.
Der Trick besteht darin, Ihr ursprüngliches Array als strukturiertes Array anzuzeigen, wobei jedes Element einer Zeile des ursprünglichen Arrays entspricht. Dies macht keine Kopie und ist sehr effizient.
Als schnelles Beispiel:
Schauen Sie sich die Zwischenergebnisse an, um zu verstehen, was los ist.
Sobald wir die Dinge als strukturiertes Array betrachten, ist jedes Element im Array eine Zeile in Ihrem ursprünglichen Array. (Grundsätzlich ist es eine ähnliche Datenstruktur wie eine Liste von Tupeln.)
Sobald wir ausgeführt werden
numpy.unique
, erhalten wir ein strukturiertes Array zurück:Das müssen wir dann als "normales" Array anzeigen (
_
speichert das Ergebnis der letzten Berechnung inipython
, weshalb Sie sehen_.view...
):Und dann wieder in ein 2D-Array umformen (
-1
ist ein Platzhalter, der numpy anweist, die richtige Anzahl von Zeilen zu berechnen und die Anzahl der Spalten anzugeben):Wenn Sie präziser sein möchten, können Sie dies natürlich wie folgt schreiben:
Was in ... endet:
quelle
lexsort
. Ich dachte, Sie beziehen sich auf die Verwendung einer Liste von Tupeln. Ja,lexsort
ist in diesem Fall wahrscheinlich die bessere Option. Ich hatte es vergessen und war zu einer übermäßig komplexen Lösung gesprungen.np.unique
Wenn ich es ausführe, werdennp.random.random(100).reshape(10,10)
alle eindeutigen Einzelelemente zurückgegeben, aber Sie möchten die eindeutigen Zeilen, also müssen Sie sie zuerst in Tupel setzen:Nur so sehe ich, dass Sie die Typen ändern, um das zu tun, was Sie wollen, und ich bin mir nicht sicher, ob die Listeniteration, die in Tupel geändert werden soll, in Ordnung ist, wenn Sie nicht durchlaufen.
quelle
< 100
Zeilen pro Aufruf habe. Dies beschreibt genau, wie das Ausführen von eindeutigen Zeilen ausgeführt wird.uniques
enthält eindeutige Elemente. Möglicherweise missverstehe ich die erwartete Form vonarray
- könnten Sie hier genauer sein?uniques
sortiert sind (und sich daher von den Zeilen in unterscheidenarray
).B = np.array([[1,2],[2,1]]); A = np.unique([tuple(row) for row in B]); print(A) = array([[1, 2],[1, 2]])
np.unique sortiert ein abgeflachtes Array und prüft dann, ob jedes Element dem vorherigen entspricht. Dies kann manuell ohne Abflachung erfolgen:
Diese Methode verwendet keine Tupel und sollte viel schneller und einfacher sein als andere hier angegebene Methoden.
HINWEIS: Eine frühere Version davon hatte nicht das Ind direkt nach einem [, was bedeutet, dass die falschen Indizes verwendet wurden. Außerdem macht Joe Kington einen guten Punkt , dass dies tut eine Vielzahl von Zwischenkopien machen. Die folgende Methode macht weniger, indem sie eine sortierte Kopie erstellt und dann Ansichten davon verwendet:
Dies ist schneller und benötigt weniger Speicher.
Wenn Sie eindeutige Zeilen in einem ndarray suchen möchten, unabhängig davon, wie viele Dimensionen sich im Array befinden, funktioniert Folgendes:
Ein interessantes verbleibendes Problem wäre, wenn Sie entlang einer beliebigen Achse eines Arrays mit beliebigen Dimensionen sortieren / eindeutig sein möchten, was schwieriger wäre.
Bearbeiten:
Um die Geschwindigkeitsunterschiede zu demonstrieren, habe ich einige Tests in ipython der drei verschiedenen Methoden durchgeführt, die in den Antworten beschrieben sind. Mit Ihrem genauen a gibt es keinen allzu großen Unterschied, obwohl diese Version etwas schneller ist:
Mit einem größeren a ist diese Version jedoch viel, viel schneller:
quelle
a[ind[1:]]
eine Kopie usw.) Andererseits ist Ihre Lösung im Allgemeinen 2-3x schneller als meine, bis Ihnen der RAM ausgeht.dtype
in deinen Timings? Ich denke, du hast das falsch verstanden. Auf meinem System ist das Anrufennp.unique
wie in meiner Antwort beschrieben etwas schneller als das Verwenden einer Ihrer beiden Varianten vonnp.lexsort
. Und es ist ungefähr 5x schneller, wenn das Array, um Unikate zu finden, Form hat(10000, 100)
. Selbst wenn Sie sich für eine Neuimplementierung entscheiden,np.unique
um eine (geringfügige) Ausführungszeit zu verkürzen, führt das Reduzieren jeder Zeile zu einem einzelnen Objekt schnellere Vergleiche aus, als wenn Sienp.any
den Vergleich der Spalten aufrufen müssen , insbesondere bei höheren Spaltenzahlen.dtype
ist nura.dtype
der Datentyp der angezeigten Daten, wie es Joe Kington in seiner Antwort getan hat. Wenn es viele Spalten gibt, besteht eine andere (unvollständige!) Möglichkeit, die Dinge schnell zu halten,lexsort
darin, nur einige Spalten zu sortieren. Dies ist datenspezifisch, da man wissen muss, welche Spalten genügend Varianz bieten, um perfekt zu sortieren. ZBa.shape = (60000, 500)
- sortiere nach den ersten 3 Spalten :ind = np.lexsort((a[:, 2], a[:, 1], a[:, 0]))
. Die Zeitersparnis ist ziemlich beträchtlich, aber der Haftungsausschluss noch einmal: Es werden möglicherweise nicht alle Fälle erfasst - es hängt von den Daten ab.Hier ist eine weitere Variante für die @ Greg-Python-Antwort
quelle
Ich habe die vorgeschlagene Alternative auf Geschwindigkeit verglichen und festgestellt, dass die Void-View-
unique
Lösung überraschenderweiseunique
mit demaxis
Argument sogar etwas schneller ist als Numpys native . Wenn Sie Geschwindigkeit suchen, werden Sie wollenCode zur Reproduktion der Handlung:
quelle
vstack_dict
Verwenden Sie niemals ein Diktat, geschweiften Klammern ist ein festes Verständnis, und daher ist sein Verhalten fast identisch mitvstatck_set
. Da dievstack_dict
Leistungslinie für das Diagramm fehlt, sieht es so aus, als würde sie nur vomvstack_set
Leistungsdiagramm abgedeckt , da sie so ähnlich sind!vstack
Variante enthält.Ich mochte keine dieser Antworten, weil keine Gleitkomma-Arrays im Sinne einer linearen Algebra oder eines Vektorraums handhabt, wobei zwei Zeilen, die „gleich“ sind, „innerhalb eines 𝜀“ bedeuten. Bei der einen Antwort mit einem Toleranzschwellenwert, https://stackoverflow.com/a/26867764/500207 , wurde der Schwellenwert sowohl als element- als auch als dezimalgenau angenommen. Dies funktioniert in einigen Fällen, ist jedoch mathematisch nicht so allgemein wie ein wahre Vektorentfernung.
Hier ist meine Version:
Die obige Public-Domain-Funktion verwendet
scipy.spatial.distance.pdist
, um den euklidischen (anpassbaren) Abstand zwischen jedem Zeilenpaar zu ermitteln. Dann vergleicht es jede Entfernung mit einerthresh
alten, um die Zeilen zu finden, diethresh
ineinander liegen, und gibt nur eine Zeile von jedemthresh
Cluster zurück.Wie angedeutet, muss die Entfernung
metric
nicht euklidisch sein -pdist
kann verschiedene Entfernungen berechnen, einschließlichcityblock
(Manhattan-Norm) undcosine
(Winkel zwischen Vektoren).Wenn
thresh=0
(Standardeinstellung), müssen die Zeilen bitgenau sein, um als "eindeutig" zu gelten. Andere gute Werte für diethresh
Verwendung skalierter Maschinengenauigkeit, dhthresh=np.spacing(1)*1e3
.quelle
set
) als Vertreter jederthresh
Nachbarschaft mit der Größe auszuwählen, könnte die Funktion das zulassen Benutzer, um anzugeben, wie dieser Punkt ausgewählt werden soll, z. B. den „Median“ oder den Punkt, der dem Schwerpunkt am nächsten liegt, usw.thresh
Cluster ausgewählt wird, aufgrund der ungeordneten Natur von zufällig istset
. Natürlich ist das ein Brainfart auf meiner Seite ist, dieset
Geschäfte Tupeln von Indizes , die in denen sindthresh
-neighborhood, so dass diesfindRows
tut in der Tat Gegenzug für jedenthresh
-Cluster, die erste Zeile darin.Warum nicht
drop_duplicates
von Pandas verwenden:quelle
Das numpy_indexed- Paket (Haftungsausschluss: Ich bin sein Autor) verpackt die von Jaime veröffentlichte Lösung in eine schöne und getestete Oberfläche sowie viele weitere Funktionen:
quelle
np.unique arbeitet mit einer Liste von Tupeln:
Bei einer Liste von Listen wird a
TypeError: unhashable type: 'list'
quelle
Basierend auf der Antwort auf dieser Seite habe ich eine Funktion geschrieben, die die Fähigkeit der MATLAB-
unique(input,'rows')
Funktion nachbildet , mit der zusätzlichen Funktion, Toleranz für die Überprüfung der Eindeutigkeit zu akzeptieren. Es gibt auch die Indizes zurück, so dassc = data[ia,:]
unddata = c[ic,:]
. Bitte melden Sie, wenn Sie Unstimmigkeiten oder Fehler feststellen.quelle
Abgesehen von der hervorragenden Antwort von @Jaime besteht eine andere Möglichkeit, eine Zeile zu reduzieren, darin,
a.strides[0]
(vorausgesetzt, siea
ist C-zusammenhängend) zu verwenden, was gleich ista.dtype.itemsize*a.shape[0]
. Weiterhinvoid(n)
ist eine Abkürzung fürdtype((void,n))
. Wir kommen endlich zu dieser kürzesten Version:Zum
quelle
Versuchen Sie Folgendes für allgemeine Zwecke wie 3D oder höher mehrdimensionale verschachtelte Arrays:
welches Ihren 2D-Datensatz erfüllt:
gibt:
Aber auch 3D-Arrays wie:
gibt:
quelle
unique
return_index
wie Jaime sollte die letztereturn
Zeile einfacher machen. Indizieren Sie einfach das Originalar
auf der rechten Achse.Keine dieser Antworten hat bei mir funktioniert. Ich gehe davon aus, dass meine eindeutigen Zeilen Zeichenfolgen und keine Zahlen enthielten. Diese Antwort aus einem anderen Thread hat jedoch funktioniert:
Quelle: https://stackoverflow.com/a/38461043/5402386
Sie können die Methoden der Listen .count () und .index () verwenden
quelle
Wir können das numerische numpy-Array mxn tatsächlich in ein numpy-String-Array mx 1 umwandeln. Versuchen Sie es mit der folgenden Funktion. Es bietet count , inverse_idx und usw., genau wie numpy.unique:
Beispiel:
quelle
Lassen Sie uns die gesamte Numpy-Matrix als Liste abrufen, dann Duplikate aus dieser Liste löschen und schließlich unsere eindeutige Liste wieder in eine Numpy-Matrix zurückgeben:
quelle
Die einfachste Lösung besteht darin, die Zeilen zu einem einzelnen Element zu machen, indem Sie sie zu Zeichenfolgen machen. Jede Zeile kann dann mit numpy als Ganzes auf ihre Einzigartigkeit hin verglichen werden. Diese Lösung ist verallgemeinerbar. Sie müssen lediglich Ihr Array umformen und für andere Kombinationen transponieren. Hier ist die Lösung für das bereitgestellte Problem.
Wird geben:
Schicken Sie meinen Nobelpreis per Post
quelle
quelle