Ich bin kürzlich auf einen großartigen SO-Beitrag gestoßen, in dem ein Benutzer vorschlägt Das numpy.sum
ist schneller als Pythons sum
, wenn es um den Umgang mit NumPy-Arrays geht.
Das hat mich dazu gebracht, zu denken, sind Element-weise Operationen auf NumPy-Arrays schneller mit NumPy-Funktionen als Operatoren? Wenn ja, warum ist das der Fall?
Betrachten Sie das folgende Beispiel.
%Vor% Wird np.subtract(a, b)
zuverlässig schneller sein als a - b
?
Nein, nicht in signifikanter Weise.
Der Grund np.sum
ist schneller als sum
ist, dass sum
implementiert ist, um "naiv" über das iterierbare (in diesem Fall das numpy array), aufrufende Elemente ' __add__
operator (was ein a signifikanter Overhead), während die Implementierung von sum
von numpy optimiert ist, z Ausnutzen der Tatsache, dass es den Typ (dtype) der Elemente kennt und dass sie zusammenhängend im Speicher sind.
Dies ist bei np.subtract(arr1, arr2)
und arr1-arr2
nicht der Fall. Letzteres entspricht grob dem ersten.
Der Unterschied ergibt sich daraus, dass man den Subtraktionsoperator in Python überschreiben kann, so dass numpy Arrays ihn überschreiben, um die optimierte Version zu verwenden. Die Operation sum
ist jedoch nicht überschreibbar, daher stellt numpy eine alternative optimierte Version davon zur Verfügung.
Nicht wirklich. Sie können die Zeiten aber ziemlich einfach überprüfen.
%Vor%Die numpigen Funktionen scheinen tatsächlich etwas langsamer zu sein. Ich bin mir nicht sicher, ob das wichtig ist, aber ich vermute, dass es aufgrund eines zusätzlichen Funktionsaufruf-Overhead über der gleichen Implementierung liegen könnte.
BEARBEITEN: Wie @unutbu bemerkt, liegt es wahrscheinlich daran, dass np.add
und Freunde zusätzlichen Typprüfaufwand haben, um array-likes bei Bedarf in Arrays umzuwandeln, also so etwas wie np.add([1, 2], [3, 4])
.
Große Antwort von @ shx2.
Ich werde nur geringfügig auf sum
vs. np.sum
:
sum
durchlaufen ein Array, nehmen die Elemente einzeln und jedes in ein Python-Objekt um, bevor sie zusammen als Python-Objekte hinzugefügt werden. np.sum
summiert das Array unter Verwendung einer optimierten Schleife in nativem Code, ohne irgendeine Umwandlung der einzelnen Werte (wie shx2 zeigt, erfordert dies entscheidend Homogenität und Kontiguität des Array-Inhalts) Die Konvertierung jedes Array-Elements in ein Python-Objekt ist bei weitem die Hauptquelle für den Overhead.
Das erklärt übrigens auch, warum dumm Pythons Standard-Python verwendet. Bibliothek C-Array-Typ für Mathematik. sum(list)
ist viel viel schneller als sum(array.array)
.
a-b
wird in einen Funktionsaufruf a.__rsub__(b)
übersetzt. Daher verwendet es die Methode, die zu der Variablen gehört (z. B. kompilierter numpy-Code, wenn a
ein Array ist).
Das Dokument für np.subtract(x1, x2[, out])
zeigt an, dass es sich um ufunc
handelt. ufunc
verwendet häufig die kompilierten Operationen wie __rsub__
, kann jedoch etwas Overhead hinzufügen, um das ufunc
-Protokoll anzupassen.
In einigen anderen Fällen wird np.foo(x, args)
in x.foo(args)
übersetzt.
Wenn die Funktionen und Operatoren den compilierten numpy Code aufrufen, um die eigentlichen Berechnungen auszuführen, werden die Timings im Allgemeinen sehr ähnlich sein, besonders bei großen Arrays.
Tags und Links python arrays performance numpy element