2010-12-21 5 views
9

Funkcja numpy vectorize jest przydatna, ale nie zachowuje się dobrze, gdy argumenty funkcji są listami, a nie skalarami. Jako przykład:Wektoryzacja Numpy, używanie list jako argumentów

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) 

Daje:

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 

Rozumiem, że funkcja f działa dobrze bez vectorize ing go, ale chciałbym wiedzieć, jak (w ogóle) Wektoryzacji funkcja, której argumenty przyjmują raczej listy niż skalar.

Odpowiedz

11

Twoje pytanie nie wyjaśnia dokładnie, jakie wyjście chciałbyś zobaczyć z funkcji wektorowej, ale zakładam, że chciałbyś, aby ta sama lista (A) była stosowana jako argument przy każdym wywołaniu f () (tj. raz dla każdego elementu w tablicy X)

Wektoryzowana wersja funkcji zapewnia, że ​​wszystkie argumenty są tablicami, a następnie stosuje się numpy's broadcasting rules w celu określenia sposobu łączenia tych argumentów.

Podobnie jak w przypadku np.array zawijania np.ndarray, przymus argumentów do tablic próbuje być pomocny, automatycznie przekształcając listę w tablicę zawierającą te same elementy, zamiast tworzyć tablicę z dtype = object zawiera listę jako jedyny element. Najczęściej to jest to, czego chcemy, ale w twoim przypadku to "inteligentne" zachowanie wraca, by cię ugryźć.

Chociaż nie może być sposobem na instruować numpy tylko w leczeniu niektórych wejść jako wektory, są dwa proste sposoby, aby uzyskać zachowanie jesteś po:

  1. ręcznie utworzyć takie array with dtype=object do pracy w radiofonii zasady
  2. Curry wartość przed Wektoryzacja obok funkcji

1. dtype = obiekt

tablice numpy czerpią swoją efektywność z tylko przechowywania jeden typ elementu, ale mogą zawierać dowolne obiekty, określając, że składowany typu dane są obiekty Pythona:

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 

drukuje:

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] 

i powroty:

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

2.Currying

Ponieważ są przechodzącą tej samej listy do wywołania funkcji dla każdego elementu w tablicy, można przechowywać listę bezpośrednio z funkcji przez currying przed stosujące wektoryzacji:

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) 

odbitek:

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] 

i powroty:

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

P.S. możesz również chcieć rzucić okiem na np.frompyfunc - jest podobny do wektoryzacji(), ale działa na nieco niższym poziomie.

0

To jest przykład rekurencyjnej dekoratora obecnie używam do wektoryzacji funkcję, która pobiera tablicę 1D jako pierwszy 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 

Chyba nie całkiem tak samo jak np.vectorize, ale łatwiej mi było z tego skorzystać, niż próbować przystosować do tego zadania vectorize/frompyfunc.