2010-12-21 15 views
9

Die Funktion numpy vectorize ist nützlich, aber es verhält sich nicht gut, wenn die Funktionsargumente Listen und nicht Skalare sind. Als Beispiel:Numpy vectorize, mit Listen als Argumente

import numpy as np 

def f(x, A): 
    print "type(A)=%s, A=%s"%(type(A),A) 
    return sum(A)/x 

X = np.linspace(1,2,10) 
P = [1,2,3] 

f2 = np.vectorize(f) 

f(X,P) 
f2(X,P) 

Gibt:

type(A)=<type 'list'>, A=[1, 2, 3] 
type(A)=<type 'numpy.int64'>, A=1 

Traceback (most recent call last): 
    File "vectorize.py", line 14, in <module> 
    f2(X,P) 
    File "/usr/local/lib/python2.6/dist-packages/numpy/lib/function_base.py", line 1824, in __call__ 
    theout = self.thefunc(*newargs) 
    File "vectorize.py", line 5, in f 
    return sum(A)/x 
TypeError: 'numpy.int64' object is not iterable 

Ich verstehe, dass die Funktion f gerade fein ohne vectorize ing es funktioniert, aber ich würde gerne wissen, wie (im Allgemeinen) vectorize eine Funktion, deren Argumente Listen statt eines Skalars aufnehmen.

Antwort

11

Ihre Frage macht nicht genau klar, welche Ausgabe Sie von der vektorisierten Funktion sehen möchten, aber ich gehe davon aus, dass Sie dieselbe Liste (A) als Argument für jeden Aufruf von f verwenden möchten () (dh einmal für jedes Element im X-Array)

Die vektorisierte Version einer Funktion stellt sicher, dass alle Argumente Arrays sind, und wendet dann numpy's broadcasting rules an, um zu bestimmen, wie diese Argumente kombiniert werden sollen.

Wie beim Wrapping von np.narray durch np.array versucht der Zwang der Argumente für Arrays hilfreich zu sein, indem er eine Liste automatisch in ein Array mit denselben Elementen konvertiert, anstatt ein Array mit dtype = object zu erstellen enthält die Liste als einziges Element. Meistens ist es das, was wir wollen, aber in deinem Fall kommt dieses "intelligente" Verhalten zurück, um dich zu beißen.

Während es eine Möglichkeit sein kann numpy nur anweisen, behandeln bestimmte Eingaben als Vektoren, gibt es zwei einfache Möglichkeiten, um das Verhalten sind Sie nach zu bekommen:

  1. manuell eine array with dtype=object erstellen im Rundfunk zu arbeiten Regeln
  2. Curry der Wert vor der Vektorisierung der Funktion

1. dtype = Objekt

012.351.

Numpy Arrays leiten ihre Effizienz von nur einer Art von Element zu speichern, aber sie können noch beliebige Python Objekte enthalten, durch die Angabe, dass die Datenart Python-Objekte gespeichert werden:

list_obj_array = np.ndarray((1,), dtype=object) 
list_obj_array[0] = [1,2,3] 
f2(X,list_obj_array) # using your definition from above 

Drucke:

type(A)=<type 'list'>, A=[1, 2, 3] 
type(A)=<type 'list'>, A=[1, 2, 3] 
type(A)=<type 'list'>, A=[1, 2, 3] 
type(A)=<type 'list'>, A=[1, 2, 3] 
type(A)=<type 'list'>, A=[1, 2, 3] 
type(A)=<type 'list'>, A=[1, 2, 3] 
type(A)=<type 'list'>, A=[1, 2, 3] 
type(A)=<type 'list'>, A=[1, 2, 3] 
type(A)=<type 'list'>, A=[1, 2, 3] 
type(A)=<type 'list'>, A=[1, 2, 3] 
type(A)=<type 'list'>, A=[1, 2, 3] 

und kehrt:

array([ 6.  , 5.4  , 4.90909091, 4.5  , 4.15384615, 
     3.85714286, 3.6  , 3.375  , 3.17647059, 3.  ]) 

2.Currying

Da Sie die gleiche Liste mit dem Funktionsaufruf sind vorbei für jedes Element im Array, können Sie die Liste speichern, direkt mit der Funktion von currying vor der Anwendung Vektorisierung:

def curry_f(A): 
    def f_curried(x): 
     return f(x, A) # using your definition from above 
    return f_curried 

f2 = np.vectorize(curry_f(P)) 
f2(X) 

druckt:

type(A)=<type 'list'>, A=[1, 2, 3] 
type(A)=<type 'list'>, A=[1, 2, 3] 
type(A)=<type 'list'>, A=[1, 2, 3] 
type(A)=<type 'list'>, A=[1, 2, 3] 
type(A)=<type 'list'>, A=[1, 2, 3] 
type(A)=<type 'list'>, A=[1, 2, 3] 
type(A)=<type 'list'>, A=[1, 2, 3] 
type(A)=<type 'list'>, A=[1, 2, 3] 
type(A)=<type 'list'>, A=[1, 2, 3] 
type(A)=<type 'list'>, A=[1, 2, 3] 

und kehrt:

array([ 6.  , 5.4  , 4.90909091, 4.5  , 4.15384615, 
     3.85714286, 3.6  , 3.375  , 3.17647059, 3.  ]) 

PS Vielleicht möchten Sie auch np.frompyfunc betrachten - es ist ähnlich wie vectorize(), aber arbeitet auf einer etwas niedrigeren Ebene.

0

Dies ist ein Beispiel eines rekursiven Dekorateur ich zur Zeit mit einer Funktion vektorisieren, die eine 1D-Array als erstes Argument:

def broadcast(fvec): 
    def inner(vec, *args, **kwargs): 
     if len(vec.shape) > 1: 
      return np.array([inner(row, *args, **kwargs) for row in vec]) 
     else: 
      return fvec(vec, *args, **kwargs) 
    return inner 

Ich denke, es tut so ziemlich das gleiche wie np.vectorize, aber Es stellte sich heraus, dass es einfacher für mich war, dies zu versuchen als vectorize/frompyfunc für den Job anzupassen.