Il s'agit d'une fonction sigmoïde logistique:
Je sais x. Comment puis-je calculer F (x) en Python maintenant?
Disons x = 0,458.
F (x) =?
Il s'agit d'une fonction sigmoïde logistique:
Je sais x. Comment puis-je calculer F (x) en Python maintenant?
Disons x = 0,458.
F (x) =?
Réponses:
Cela devrait le faire:
import math
def sigmoid(x):
return 1 / (1 + math.exp(-x))
Et maintenant, vous pouvez le tester en appelant:
>>> sigmoid(0.458)
0.61253961344091512
Mise à jour : Notez que ce qui précède était principalement conçu comme une traduction directe un à un de l'expression donnée en code Python. Il n'est pas testé ou connu pour être une mise en œuvre numériquement solide. Si vous savez que vous avez besoin d'une implémentation très robuste, je suis sûr qu'il y en a d'autres où les gens ont réfléchi à ce problème.
math.exp
par, np.exp
vous n'obtiendrez pas de NaN, bien que vous obteniez des avertissements d'exécution.
math.exp
avec tableau numpy peut donner des erreurs, comme: TypeError: only length-1 arrays can be converted to Python scalars
. Pour éviter cela, vous devez utiliser numpy.exp
.
x = max(-709,x)
avant l'expression?
Il est également disponible dans scipy: http://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.logistic.html
In [1]: from scipy.stats import logistic
In [2]: logistic.cdf(0.458)
Out[2]: 0.61253961344091512
qui n'est qu'un wrapper coûteux (car il vous permet de mettre à l'échelle et de traduire la fonction logistique) d'une autre fonction scipy:
In [3]: from scipy.special import expit
In [4]: expit(0.458)
Out[4]: 0.61253961344091512
Si vous êtes préoccupé par les performances, continuez à lire, sinon utilisez simplement expit
.
In [5]: def sigmoid(x):
....: return 1 / (1 + math.exp(-x))
....:
In [6]: %timeit -r 1 sigmoid(0.458)
1000000 loops, best of 1: 371 ns per loop
In [7]: %timeit -r 1 logistic.cdf(0.458)
10000 loops, best of 1: 72.2 µs per loop
In [8]: %timeit -r 1 expit(0.458)
100000 loops, best of 1: 2.98 µs per loop
Comme prévu, logistic.cdf
c'est (beaucoup) plus lent que expit
. expit
est toujours plus lente que la sigmoid
fonction python lorsqu'elle est appelée avec une seule valeur car il s'agit d'une fonction universelle écrite en C ( http://docs.scipy.org/doc/numpy/reference/ufuncs.html ) et a donc une surcharge d'appel. Cette surcharge est plus grande que la vitesse de calcul expit
donnée par sa nature compilée lorsqu'elle est appelée avec une seule valeur. Mais cela devient négligeable lorsqu'il s'agit de grands tableaux:
In [9]: import numpy as np
In [10]: x = np.random.random(1000000)
In [11]: def sigmoid_array(x):
....: return 1 / (1 + np.exp(-x))
....:
(Vous remarquerez le petit changement de math.exp
à np.exp
(le premier ne prend pas en charge les tableaux, mais est beaucoup plus rapide si vous n'avez qu'une seule valeur à calculer))
In [12]: %timeit -r 1 -n 100 sigmoid_array(x)
100 loops, best of 1: 34.3 ms per loop
In [13]: %timeit -r 1 -n 100 expit(x)
100 loops, best of 1: 31 ms per loop
Mais lorsque vous avez vraiment besoin de performances, une pratique courante consiste à avoir un tableau précalculé de la fonction sigmoïde qui contient de la RAM, et à échanger une certaine précision et mémoire contre une certaine vitesse (par exemple: http://radimrehurek.com/2013/09 / word2vec-in-python-part-two-optimizing / )
Notez également que l' expit
implémentation est numériquement stable depuis la version 0.14.0: https://github.com/scipy/scipy/issues/3385
Voici comment implémenter le sigmoïde logistique de manière numériquement stable (comme décrit ici ):
def sigmoid(x):
"Numerically-stable sigmoid function."
if x >= 0:
z = exp(-x)
return 1 / (1 + z)
else:
z = exp(x)
return z / (1 + z)
Ou peut-être est-ce plus précis:
import numpy as np
def sigmoid(x):
return math.exp(-np.logaddexp(0, -x))
En interne, il implémente la même condition que ci-dessus, mais utilise ensuite log1p
.
En général, le sigmoïde logistique multinomial est:
def nat_to_exp(q):
max_q = max(0.0, np.max(q))
rebased_q = q - max_q
return np.exp(rebased_q - np.logaddexp(-max_q, np.logaddexp.reduce(rebased_q)))
(Cependant, cela logaddexp.reduce
pourrait être plus précis.)
max_q
et rebased_q
par tau
? parce que j'ai essayé cela et je n'obtiens pas de probabilités qui
q
) par votre température. rebased_q peut être n'importe quoi: cela ne change pas la réponse; il améliore la stabilité numérique.
nat_to_exp
est équivalent à softmax (comme vous l'avez mentionné dans votre autre réponse)? Copier-coller de celui-ci renvoie des probabilités qui ne
autrement
>>> def sigmoid(x):
... return 1 /(1+(math.e**-x))
...
>>> sigmoid(0.458)
pow
est souvent implémenté en termes de exp
et log
, donc l'utilisation exp
directe est presque certainement meilleure.
x
est très négatif.
Une autre façon en transformant la tanh
fonction:
sigmoid = lambda x: .5 * (math.tanh(.5 * x) + 1)
Je pense que beaucoup pourraient être intéressés par des paramètres libres pour modifier la forme de la fonction sigmoïde. Deuxièmement, pour de nombreuses applications, vous souhaitez utiliser une fonction sigmoïde en miroir. Troisièmement, vous voudrez peut-être faire une normalisation simple, par exemple, les valeurs de sortie sont comprises entre 0 et 1.
Essayer:
def normalized_sigmoid_fkt(a, b, x):
'''
Returns array of a horizontal mirrored normalized sigmoid function
output between 0 and 1
Function parameters a = center; b = width
'''
s= 1/(1+np.exp(b*(x-a)))
return 1*(s-min(s))/(max(s)-min(s)) # normalize function to 0-1
Et pour dessiner et comparer:
def draw_function_on_2x2_grid(x):
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2)
plt.subplots_adjust(wspace=.5)
plt.subplots_adjust(hspace=.5)
ax1.plot(x, normalized_sigmoid_fkt( .5, 18, x))
ax1.set_title('1')
ax2.plot(x, normalized_sigmoid_fkt(0.518, 10.549, x))
ax2.set_title('2')
ax3.plot(x, normalized_sigmoid_fkt( .7, 11, x))
ax3.set_title('3')
ax4.plot(x, normalized_sigmoid_fkt( .2, 14, x))
ax4.set_title('4')
plt.suptitle('Different normalized (sigmoid) function',size=10 )
return fig
Finalement:
x = np.linspace(0,1,100)
Travel_function = draw_function_on_2x2_grid(x)
Bonne réponse de @unwind. Il ne peut cependant pas gérer un nombre négatif extrême (lançant OverflowError).
Mon amélioration:
def sigmoid(x):
try:
res = 1 / (1 + math.exp(-x))
except OverflowError:
res = 0.0
return res
Tensorflow comprend également une sigmoid
fonction:
https://www.tensorflow.org/versions/r1.2/api_docs/python/tf/sigmoid
import tensorflow as tf
sess = tf.InteractiveSession()
x = 0.458
y = tf.sigmoid(x)
u = y.eval()
print(u)
# 0.6125396
Une version numériquement stable de la fonction sigmoïde logistique.
def sigmoid(x):
pos_mask = (x >= 0)
neg_mask = (x < 0)
z = np.zeros_like(x,dtype=float)
z[pos_mask] = np.exp(-x[pos_mask])
z[neg_mask] = np.exp(x[neg_mask])
top = np.ones_like(x,dtype=float)
top[neg_mask] = z[neg_mask]
return top / (1 + z)
Une seule doublure ...
In[1]: import numpy as np
In[2]: sigmoid=lambda x: 1 / (1 + np.exp(-x))
In[3]: sigmoid(3)
Out[3]: 0.9525741268224334
pandas DataFrame/Series
ou numpy array
:Les principales réponses sont des méthodes optimisées pour le calcul d'un point unique, mais lorsque vous souhaitez appliquer ces méthodes à une série pandas ou à un tableau numpy, cela nécessite apply
, ce qui est essentiellement une boucle pour en arrière-plan et itérera sur chaque ligne et appliquera la méthode. C'est assez inefficace.
Pour accélérer notre code, nous pouvons utiliser la vectorisation et la diffusion numpy:
x = np.arange(-5,5)
np.divide(1, 1+np.exp(-x))
0 0.006693
1 0.017986
2 0.047426
3 0.119203
4 0.268941
5 0.500000
6 0.731059
7 0.880797
8 0.952574
9 0.982014
dtype: float64
Ou avec un pandas Series
:
x = pd.Series(np.arange(-5,5))
np.divide(1, 1+np.exp(-x))
vous pouvez le calculer comme:
import math
def sigmoid(x):
return 1 / (1 + math.exp(-x))
ou conceptuel, plus profond et sans aucune importation:
def sigmoid(x):
return 1 / (1 + 2.718281828 ** -x)
ou vous pouvez utiliser numpy pour les matrices:
import numpy as np #make sure numpy is already installed
def sigmoid(x):
return 1 / (1 + np.exp(-x))
import numpy as np
def sigmoid(x):
s = 1 / (1 + np.exp(-x))
return s
result = sigmoid(0.467)
print(result)
Le code ci-dessus est la fonction sigmoïde logistique en python. Si je sais que x = 0.467
, la fonction sigmoïde, F(x) = 0.385
. Vous pouvez essayer de remplacer n'importe quelle valeur de x que vous connaissez dans le code ci-dessus, et vous obtiendrez une valeur différente de F(x)
.
sigmoid = lambda x: 1 / (1 + math.exp(-x))