2016-08-01 31 views
1

Ich habe Probleme, eine mehrdimensionale Funktion zu vektorisieren.
Betrachten Sie das folgende Beispiel:numpy vectorize mehrdimensionale Funktion

def _cost(u): 
    return u[0] - u[1] 

cost = np.vectorize(_cost) 

>>> x = np.random.normal(0, 1,(10, 2)) 
>>> cost(x) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/Users/lucapuggini/MyApps/scientific_python_3_5/lib/python3.5/site-packages/numpy/lib/function_base.py", line 2218, in __call__ 
    return self._vectorize_call(func=func, args=vargs) 
    File "/Users/lucapuggini/MyApps/scientific_python_3_5/lib/python3.5/site-packages/numpy/lib/function_base.py", line 2281, in _vectorize_call 
    ufunc, otypes = self._get_ufunc_and_otypes(func=func, args=args) 
    File "/Users/lucapuggini/MyApps/scientific_python_3_5/lib/python3.5/site-packages/numpy/lib/function_base.py", line 2243, in _get_ufunc_and_otypes 
    outputs = func(*inputs) 
TypeError: _cost() missing 1 required positional argument: 'v' 

Hintergrundinformationen: ich das aufgetretene Problem beim Versuch, den folgenden Code (Particle Swarm Optimization Algorithm) auf multivariate Daten zu verallgemeinern:

import numpy as np 
import matplotlib.pyplot as plt 


def pso(cost, sim, space_dimension, n_particles, left_lim, right_lim, f1=1, f2=1, verbose=False): 

    best_scores = np.array([np.inf]*n_particles) 
    best_positions = np.zeros(shape=(n_particles, space_dimension)) 
    particles = np.random.uniform(left_lim, right_lim, (n_particles, space_dimension)) 
    velocities = np.zeros(shape=(n_particles, space_dimension)) 

    for i in range(sim): 
     particles = particles + velocities 
     print(particles) 
     scores = cost(particles).ravel() 
     better_positions = np.argwhere(scores < best_scores).ravel() 
     best_scores[better_positions] = scores[better_positions] 
     best_positions[better_positions, :] = particles[better_positions, :] 
     g = best_positions[np.argmin(best_scores), :] 

     u1 = np.random.uniform(0, f1, (n_particles, 1)) 
     u2 = np.random.uniform(0, f2, (n_particles, 1)) 
     velocities = velocities + u1 * (best_positions - particles) + u2 * (g - particles) 

     if verbose and i % 50 == 0: 
      print('it=', i, ' score=', cost(g)) 


      x = np.linspace(-5, 20, 1000) 
      y = cost(x) 

      plt.plot(x, y) 
      plt.plot(particles, cost(particles), 'o') 
      plt.vlines(g, y.min()-2, y.max()) 
      plt.show() 


    return g, cost(g) 




def test_pso_1_dim(): 

    def _cost(x): 
     if 0 < x < 15: 
      return np.sin(x)*x 
     else: 
      return 15 + np.min([np.abs(x-0), np.abs(x-15)]) 

    cost = np.vectorize(_cost) 

    sim = 100 
    space_dimension = 1 
    n_particles = 5 
    left_lim, right_lim = 0, 15 
    f1, f2 = 1, 1 

    x, cost_x = pso(cost, sim, space_dimension, n_particles, 
        left_lim, right_lim, f1, f2, verbose=False) 

    x0 = 11.0841839 
    assert np.abs(x - x0) < 0.01 

    return 

Bitte geben Sie mir, wenn Vektorisierung ist in diesem Fall keine gute Idee.

Antwort

1

Wie in den Erläuterungen erwähnt für vectorize:

Die Vektorisieren Funktion ist in erster Linie für die Bequemlichkeit vorgesehen sind, nicht für die Leistung. Die Implementierung ist im Wesentlichen eine for-Schleife.

So, während Ihr Code Vektorisierung eine gute Idee sein kann, über numpy Typen und Funktionen, werden Sie wahrscheinlich sollte diese numpy.vectorize mit nicht tun.

auf Ihre Funktion
def cost(x): 
    # Create the empty output 
    output = np.empty(x.shape) 
    # Select the first group using a boolean array 
    group1 = (0 < x) & (x < 15) 
    output[group1] = np.sin(x[group1])*x[group1] 
    # Select second group as inverse (logical not) of group1 
    output[~group1] = 15 + np.min(
     [np.abs(x[~group1]-0), np.abs(x[~group1]-15)], 
     axis=0) 
    return output 
0

np.vectorize Feeds Skalare:

Für das Beispiel ihr habt, könnte Ihr cost einfach und effizient als Funktion arbeitet auf einem numpy Array berechnet werden. Zum Beispiel:

In [1090]: def _cost(u): 
     ...:  return u*2 

In [1092]: cost=np.vectorize(_cost) 
In [1093]: cost(np.arange(10) 
     ...:) 
Out[1093]: array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18]) 
In [1094]: cost(np.ones((3,4))) 
Out[1094]: 
array([[ 2., 2., 2., 2.], 
     [ 2., 2., 2., 2.], 
     [ 2., 2., 2., 2.]]) 

Aber Ihre Funktion verhält sich so, als würde sie eine Liste oder ein Array mit 2 Werten erhalten. Was beabsichtigtest du?

eine Funktion mit 2 Skalare:

In [1095]: def _cost(u,v): 
     ...:  return u+v 
     ...:  
     ...: 
In [1096]: cost=np.vectorize(_cost) 

In [1098]: cost(np.arange(3),np.arange(3,6)) 
Out[1098]: array([3, 5, 7]) 

In [1099]: cost([[1],[2]],np.arange(3,6)) 
Out[1099]: 
array([[4, 5, 6], 
     [5, 6, 7]]) 

Oder mit 2 Säulen x:

In [1103]: cost(x[:,0],x[:,1]) 
Out[1103]: 
array([-1.7291913 , -0.46343403, 0.61574928, 0.9864683 , -1.22373097, 
     1.01970917, 0.22862683, -0.11653917, -1.18319723, -3.39580376]) 

die als dabei eine Anordnung Summe auf der Achse 1 ist die gleiche

In [1104]: x.sum(axis=1) 
Out[1104]: 
array([-1.7291913 , -0.46343403, 0.61574928, 0.9864683 , -1.22373097, 
     1.01970917, 0.22862683, -0.11653917, -1.18319723, -3.39580376])