Gibt es in Bezug auf diese Antwort eine schnelle Möglichkeit, Mediane über ein Array zu berechnen, das Gruppen mit einer ungleichen Anzahl von Elementen enthält?
Z.B:
data = [1.00, 1.05, 1.30, 1.20, 1.06, 1.54, 1.33, 1.87, 1.67, ... ]
index = [0, 0, 1, 1, 1, 1, 2, 3, 3, ... ]
Und dann möchte ich die Differenz zwischen der Anzahl und dem Median pro Gruppe berechnen (z. B. der Median der Gruppe 0
ist 1.025
also das erste Ergebnis 1.00 - 1.025 = -0.025
). Für das obige Array würden die Ergebnisse wie folgt aussehen:
result = [-0.025, 0.025, 0.05, -0.05, -0.19, 0.29, 0.00, 0.10, -0.10, ...]
Da np.median.reduceat
ist (noch) nicht vorhanden ist , gibt es eine weitere schnelle Möglichkeit , dies zu erreichen? Mein Array wird Millionen von Zeilen enthalten, daher ist Geschwindigkeit entscheidend!
Es kann davon ausgegangen werden, dass Indizes zusammenhängend und geordnet sind (es ist einfach, sie zu transformieren, wenn dies nicht der Fall ist).
Beispieldaten für Leistungsvergleiche:
import numpy as np
np.random.seed(0)
rows = 10000
cols = 500
ngroup = 100
# Create random data and groups (unique per column)
data = np.random.rand(rows,cols)
groups = np.random.randint(ngroup, size=(rows,cols)) + 10*np.tile(np.arange(cols),(rows,1))
# Flatten
data = data.ravel()
groups = groups.ravel()
# Sort by group
idx_sort = groups.argsort()
data = data[idx_sort]
groups = groups[idx_sort]
quelle
scipy.ndimage.median
Vorschlag in der verknüpften Antwort zeitlich festgelegt ? Es scheint mir nicht, dass es eine gleiche Anzahl von Elementen pro Etikett benötigt. Oder habe ich etwas verpasst?Antworten:
Manchmal müssen Sie nicht-idiomatischen Numpy-Code schreiben, wenn Sie Ihre Berechnung wirklich beschleunigen möchten, was mit nativem Numpy nicht möglich ist.
numba
Kompiliert Ihren Python-Code auf Low-Level C. Da viele Numpys selbst normalerweise so schnell wie C sind, ist dies meistens nützlich, wenn sich Ihr Problem nicht für eine native Vektorisierung mit Numpys eignet. Dies ist ein Beispiel (bei dem ich angenommen habe, dass die Indizes zusammenhängend und sortiert sind, was sich auch in den Beispieldaten widerspiegelt):Und hier sind einige Timings mit IPythons
%timeit
Magie:Unter Verwendung der aktualisierten Beispieldaten in der Frage sind diese Zahlen (dh die Laufzeit der Python-Funktion im Vergleich zur Laufzeit der JIT-beschleunigten Funktion)
Dies entspricht einer 65-fachen Beschleunigung im kleineren Fall und einer 26-fachen Beschleunigung im größeren Fall (natürlich im Vergleich zu langsamem Schleifencode) unter Verwendung des beschleunigten Codes. Ein weiterer Vorteil ist, dass wir (im Gegensatz zur typischen Vektorisierung mit nativem Numpy) keinen zusätzlichen Speicher benötigten, um diese Geschwindigkeit zu erreichen. Es geht um optimierten und kompilierten Low-Level-Code, der letztendlich ausgeführt wird.
Bei der obigen Funktion wird davon ausgegangen, dass numpy int-Arrays
int64
standardmäßig verwendet werden, was unter Windows nicht der Fall ist. Eine Alternative besteht darin, die Signatur aus dem Aufruf von zu entfernennumba.njit
und eine ordnungsgemäße Just-in-Time-Kompilierung auszulösen. Dies bedeutet jedoch, dass die Funktion während der ersten Ausführung kompiliert wird, was sich in Timing-Ergebnisse einmischen kann (wir können die Funktion entweder einmal manuell unter Verwendung repräsentativer Datentypen ausführen oder einfach akzeptieren, dass die erste Timing-Ausführung viel langsamer sein wird, was sollte ignoriert werden). Dies ist genau das, was ich versucht habe, indem ich eine Signatur angegeben habe, die eine vorzeitige Kompilierung auslöst.Wie auch immer, im richtigen JIT-Fall ist der Dekorateur, den wir brauchen, einfach
Beachten Sie, dass die obigen Timings, die ich für die jit-kompilierte Funktion gezeigt habe, erst gelten, wenn die Funktion kompiliert wurde. Dies geschieht entweder bei der Definition (bei eifriger Kompilierung, wenn eine explizite Signatur übergeben wird
numba.njit
) oder beim ersten Funktionsaufruf (bei verzögerter Kompilierung, wenn keine Signatur übergeben wirdnumba.njit
). Wenn die Funktion nur einmal ausgeführt werden soll, sollte die Kompilierungszeit auch für die Geschwindigkeit dieser Methode berücksichtigt werden. Das Kompilieren von Funktionen lohnt sich normalerweise nur, wenn die Gesamtzeit für Kompilierung und Ausführung kürzer ist als die nicht kompilierte Laufzeit (was im obigen Fall tatsächlich der Fall ist, wenn die native Python-Funktion sehr langsam ist). Dies geschieht meistens, wenn Sie Ihre kompilierte Funktion häufig aufrufen.Wie max9111 in einem Kommentar feststellte,
numba
ist dascache
Schlüsselwort to ein wichtiges Merkmal vonjit
. Wenn Siecache=True
an übergeben,numba.jit
wird die kompilierte Funktion auf der Festplatte gespeichert, sodass die Funktion bei der nächsten Ausführung des angegebenen Python-Moduls von dort geladen und nicht neu kompiliert wird, was Ihnen auf lange Sicht wiederum Laufzeit ersparen kann.quelle
index
Daten von roganjosh enthalten ist . Ich werde eine Nachricht darüber hinterlassen, danke :)cache=True
, um eine Neukompilierung bei jedem Neustart des Interpreters zu vermeiden.Ein Ansatz wäre,
Pandas
hier nur Gebrauch zu machengroupby
. Ich habe die Eingabegrößen etwas aufgeblasen, um die Timings besser zu verstehen (da das Erstellen des DF mit Overhead verbunden ist).Gibt Folgendes
timeit
:Bei gleicher Stichprobengröße lautet der diktierte Ansatz von Aryerez :
Wenn wir jedoch die Eingaben um einen weiteren Faktor von 10 erhöhen, werden die Timings wie folgt:
Auf Kosten einer gewissen Reagilität lautet die Antwort von Divakar mit reinem Numpy jedoch:
In Anbetracht des neuen Datensatzes (der eigentlich zu Beginn hätte gesetzt werden sollen):
quelle
Vielleicht haben Sie das schon getan, aber wenn nicht, prüfen Sie, ob das schnell genug ist:
Ausgabe:
quelle
np.vectorize
handelt es sich um einen sehr dünnen Wrapper für eine Schleife, daher würde ich nicht erwarten, dass dieser Ansatz besonders schnell ist.data
undindex
alsnp.array
s wie in der Frage.Hier ist ein NumPy-basierter Ansatz, um den Binned-Median für positive Bins / Indexwerte zu erhalten:
Um unseren speziellen Fall von subtrahierten zu lösen -
quelle
df.groupby('index').transform('median')
?