2017-08-16 3 views
4

Je voudrais attribuer une fonction qui comporte une évaluation booléenne, en utilisant une méthode rapide. Voici un exemple simple. Je veux que la fonction suivante à évaluer pour arbitraire a et b:Attribution de fonction vectorielle vectorisée avec une instruction booléenne

a = 0.5 
b = 0.6 
def func(x): 
    x=max(x,a) 
    if x>b: 
     return x**2 
    else: 
     return x**3 

et je veux affecter les valeurs de la fonction dans un tableau d'une manière vectorisée (pour la vitesse):

xRange = np.arange(0, 1, 0.1) 
arr_func = func(xRange) 

Mais J'obtiens l'erreur:

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Maintenant, je sais que je peux assigner les valeurs dans une boucle. Mais ce sera lent par rapport à l'équivalent vectorisé. Puis-je contourner cette exception et toujours attribuer les valeurs de manière vectorisée?

+1

Je pense que vous pouvez utiliser https://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.vectorize.html – Lukisn

+0

N'utilisez pas 'np.vectorize' ici! –

Répondre

4

Si je lis votre code correctement, la version vectorisée serait d'utiliser un couple np.where:

def func(x): 
    x = np.where(a > x, a, x) 
    return np.where(x > b, x**2, x**3) 
+0

@DanielF - Oui, vous avez probablement raison. Cependant, cela modifierait l'argument ('xRange' dans le cas de l'exemple d'OP). Ce n'est peut-être pas souhaitable. Numpy fait déjà un tas de copies dans les deux cas - l'hypothèse (souvent correcte) que l'on fait habituellement lorsque l'on écrit un code numérique est que le surcoût des copies est faible par rapport à l'overhead des boucles python. – mgilson

+0

Vrai - Je suis surpris de passer par référence ne me trébuche pas plus compte tenu de la fréquence à laquelle je l'oublie :) Supprimé le commentaire pour éviter toute confusion –

0

Si vous voulez (ou ont) pour garder votre fonction d'origine, vous pouvez utiliser des années numpy vectorize function pour créer la version "vectorisée" qui accepte un tableau numpy comme une entrée.

Notez que cette fonction n'est fournie que pour des raisons de commodité et offre aucune amélioration des performances puisqu'elle n'implante en interne qu'une boucle for. Donc il n'y a pas de "vraie" vectorisation!

import numpy as np 

def func(x, a=0.5, b=0.6): 
    x = max(x, a) 
    if x > b: 
     return x**2 
    else: 
     return x**3 

vfunc = np.vectorize(func) # this is it! 

xRange = np.arange(0, 1, 0.1) 
arr_func = vfunc(xRange) 

print(arr_func) 

Le code ci-dessus fonctionne et produit la sortie suivante:

[ 0.125 0.125 0.125 0.125 0.125 0.125 0.36 0.49 0.64 0.81 ] 
+0

Ceci est une mauvaise idée. Vous pouvez lire la section "Notes" de la page de documentation ['vectorize'] (https://docs.scipy.org/doc/numpy/reference/generated/numpy.vectorize.html). –

+0

Merci d'avoir signalé cela. J'ai édité ma réponse pour clarifier cela. – Lukisn

2

Il est également possible d'utiliser np.select - c'est un peu verbeux que nécessaire dans ce cas, mais il est extensible à de nombreuses conditions

def func(x): 
    condlist = [ 
        x < a, 
        (x >= a) & (x <= b), 
        x > b 
       ] 
    choicelist = [ 
        a**3, 
        x**3, 
        x**2 
       ] 
    return np.select(condlist, choicelist) 

ou

def func(x): 
    condlist = [ 
        x < a, 
        x > b 
       ] 
    choicelist = [ 
        a**3, 
        x**2 
       ] 
    return np.select(condlist, choicelist, default = x**3)