2017-02-21 2 views
0

Ich habe eine Funktion f, für exapmle:schnellere Alternative zur Verwendung der `map` Funktion

def f(x): 
    return x**2 

und will ein Array über ein Intervall ausgewertet, bestehend aus f erhalten, beispielsweise das Einheitsintervall (0, 1). Wir ca dazu wie folgt vor:

import numpy as np 
X = np.arange(0,1,0.01) 
arr = np.array(list(map(f, X))) 

Doch diese letzte Zeile ist sehr zeitaufwendig, wenn die Funktion kompliziert ist (in meinem Fall ist es beinhaltet einige Integrale). Gibt es eine Möglichkeit, dies schneller zu machen? Ich bin froh, eine nicht-elegante Lösung zu haben - der Fokus liegt auf Geschwindigkeit.

+0

Ich wäre nicht besorgt über die 'map()' Overhead wenn 'X' ist nicht riesig in der Länge. Verbringe Zeit damit, dein 'f()' zu optimieren. – zwer

+0

Es ist keine Antwort auf Ihre Frage, aber eine Liste zu erstellen, nur um ein Array zu erstellen ist ziemlich ineffizient. Sie können ['fromiter()'] (https://docs.scipy.org/doc/numpy/reference/generated/numpy.fromiter.html) verwenden, um dies zu vermeiden.Sie müssen die Länge kennen, aber wenn es sich um eine Kartenoperation handelt, wissen Sie, dass sie mit dem Array übereinstimmt, über das Sie mappen. Wenn Sie jedoch mit Numpy Geschwindigkeit erreichen wollen, sollten Sie numpy-Operationen verwenden - Karten bedeuten python-seitige Schleifen und Operationen, die langsamer sind. –

+0

@zwer Einverstanden. Sie können etwas beschleunigen, indem Sie ein Listenverständnis verwenden, aber es wird die Gesamtlaufzeit nicht wesentlich verändern. Sehen Sie sich einige Experimente an, die ich gemacht habe, um diese Frage zu beantworten (http://stackoverflow.com/questions/39045396/where-does-the-performance-boost-of-map-or-list-comprehension-implementations-ov/39046254) # 39046254) –

Antwort

1

Wenn f so kompliziert ist, dass es nicht in Bezug auf den kompilierte Array-Operationen ausgedrückt werden kann, und kann nur Skalar nehmen, ich habe festgestellt, dass frompyfunc die beste Leistung gibt (ca. 2x im Vergleich zu einer expliziten Schleife)

In [76]: def f(x): 
    ...:  return x**2 
    ...: 

In [77]: foo = np.frompyfunc(f,1,1) 

In [78]: foo(np.arange(4)) 
Out[78]: array([0, 1, 4, 9], dtype=object) 

In [79]: foo(np.arange(4)).astype(int) 
Out[79]: array([0, 1, 4, 9]) 

Es gibt dtype Objekt zurück, so benötigt ein astype. np.vectorize nutzt dies ebenfalls, ist aber etwas langsamer. Beide verallgemeinern verschiedene Formen von Eingangsarray (s).

Für ein 1d Ergebnis fromiter mit map (ohne list) Teil funktioniert:

In [84]: np.fromiter((f(x) for x in range(4)),int) 
Out[84]: array([0, 1, 4, 9]) 

In [86]: np.fromiter(map(f, range(4)),int) 
Out[86]: array([0, 1, 4, 9]) 

Sie werden Ihre eigenen Timings tun in einem realistischen Fall müssen.

2

Sie könnten Listenverstehen verwenden, um die Laufzeit etwas zu verringern.

arr = [f(x) for x in range(0, 5)] # range is the interval 

Dies sollte funktionieren. Es wird jedoch die Laufzeit nur geringfügig verringern. Sie sollten sich keine Sorgen um die Laufzeit machen, wenn Sie nicht sehr große Zahlen mit map() verwenden.

1

Verwenden Sie Operationen, die auf ganzen Arrays ausgeführt werden. Zum Beispiel mit einer Funktion, die Quadrate nur den Eingang (leicht von Ihrem Beispiel korrigiert):

def f(x): 
    return x**2 

dann würden Sie gerade tun

arr = f(X) 

weil NumPy Operatoren wie ** definiert auf ganze Arrays arbeiten auf einmal.

Ihre tatsächliche Funktion ist möglicherweise nicht ganz so einfach. Du sagst, dass es Integrale gibt; Um damit ganze Array-Operationen auszuführen, müssen Sie Argumente möglicherweise anders übergeben oder ändern, was Sie zur Berechnung der Integrale verwenden. Im Allgemeinen werden Operationen mit ganzen Arrays weitaus besser abschneiden als alles, was in einer Schleife Code auf Python-Ebene aufrufen muss.

1

Sie könnten versuchen numpy.vectorize. Es ist ein sehr guter Weg, um Funktion auf Liste oder Array anzuwenden

import numpy as np 

def foo(x): 
    return x**2 

foo = np.vectorize(foo) 
arr = np.arange(10) 

In [1]: foo(arr)                      
Out[1]: array([ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81]) 
Verwandte Themen