Sind elementweise Vorgänge mit NumPy-Funktionen schneller als Operatoren?

8

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 ?

    
Gyan Veda 12.09.2014, 21:36
quelle

4 Antworten

12

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.

    
shx2 12.09.2014, 21:40
quelle
7

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]) .

    
Roger Fan 12.09.2014 21:41
quelle
3

Große Antwort von @ shx2.

Ich werde nur geringfügig auf sum vs. np.sum :

erweitern
  • eingebaute 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) .

    
Dan Lenski 12.09.2014 21:55
quelle
1

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).

%Vor%

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.

    
hpaulj 13.09.2014 08:42
quelle