Votre soupçon est en partie correct. curve_fit
passe en effet une itérable à la fonction, mais pas n'importe laquelle itérable: numpy.ndarray
. Ceux-ci arrivent à posséder des opérateurs arithmétiques vectorisés, donc
a*(exp(-(x/x0))/x0)
les tableaux d'entrée fonctionnera tout simplement élément par élément sur sans erreur (et avec une sortie correcte). Il n'y a même pas beaucoup de magie impliquée: pour chaque évaluation de la fonction, les paramètres a
et x0
seront des scalaires, seul x
est un tableau.
Maintenant, le problème avec uniDist
est qu'il ne contient pas seulement des opérateurs arithmétiques: il contient également des opérateurs de comparaison. Ces travaux très bien tant que seule une seule matrice est comparée à un scalaire:
>>> import numpy as np
>>> a = np.arange(5)
>>> a
array([0, 1, 2, 3, 4])
>>> a>2
array([False, False, False, True, True], dtype=bool)
Ce qui précède démontre que l'utilisation des opérateurs de comparaison sur un tableau et un scalaire à nouveau des résultats élément par élément. L'erreur que vous voyez se pose lorsque vous essayez d'appliquer un opérateur logique à deux de ces tableaux booléens:
>>> a>2
array([False, False, False, True, True], dtype=bool)
>>> a<4
array([ True, True, True, True, False], dtype=bool)
>>> (a>2) and (a<4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Le message d'erreur est un peu déroutant. On peut remonter au fait que python essayait de trouver un résultat unique pour array1 and array2
(qui en python natif retournerait soit un tableau basé sur leur vide). Cependant, on soupçonne que ce n'est pas ce que vous voulez faire, et résiste à la tentation de deviner.
Puisque vous voulez que votre fonction fonctionne par éléments sur les deux tableaux booléens (qui proviennent de l'opération de comparaison), vous devrez utiliser l'opérateur &
. Ceci est "binaire et" en python natif, mais pour les tableaux numpy cela vous donne le "logique et" des tableaux. Vous pouvez également utiliser numpy.logical_and
(ou dans votre cas scipy.logical_and
) d'être plus explicite:
>>> (a>2) & (a<4)
array([False, False, False, True, False], dtype=bool)
>>> np.logical_and(a>2,a<4)
array([False, False, False, True, False], dtype=bool)
Notez que pour le &
cas, vous devez toujours parenthésée vos comparaisons, car encore une fois a>2&a<4
serait ambiguë (pour le programmeur) et faux (compte tenu de ce que vous veut faire).Puisque le "binary et" des booléens se comporteront exactement comme vous l'attendez, il est prudent de réécrire votre fonction pour utiliser &
au lieu de and
pour comparer les deux comparaisons. Cependant, il reste encore une étape à modifier: dans le cas des entrées ndarray
, le if
se comportera également différemment. Python ne peut s'empêcher de faire un seul choix dans un if
, ce qui est également vrai si vous y mettez un tableau. Mais ce que vous voulez réellement faire est de contraindre les éléments de votre sortie par élément (à nouveau). Vous devez donc soit boucler votre tableau (ne le faites pas), soit refaire ce choix de façon vectorisée. Ce dernier est idiomatiques en utilisant numpy/scipy:
import scipy as sp
def uniDist(x, a, b):
return sp.where((a<=x) & (x<=b), 1.0/(b-a), 0.0)
Ce (à savoir numpy.where
) retourne un tableau de la même taille que x
. Pour les éléments dont la condition est True
, la valeur de la sortie sera 1/(b-a)
. Pour le reste, la sortie est 0
. Pour scalaire x
, la valeur de retour est un scalaire numpy. Notez que j'ai supprimé la conversion float
dans l'exemple ci-dessus, puisque avoir 1.0
dans le numérateur vous donnera certainement la vraie division, malgré votre utilisation de python 2. Bien que je suggère d'utiliser python 3, ou au moins from __future__ import division
.
Note mineure: même pour un cas scalaire, je suggère en utilisant de l'opérateur de python enchaînant pour la comparaison, qui se prête à cet effet. Ce que je veux dire, c'est que vous pouvez simplement faire if a <= x <= b: ...
, et contrairement à la plupart des langues, cela sera fonctionnellement équivalent à ce que vous avez écrit (mais plus joli).
https://docs.scipy.org/doc/numpy/user/basics.broadcasting.html – user2357112