Questa è una funzione sigmoidea logistica:
Conosco x. Come posso calcolare F (x) in Python ora?
Diciamo x = 0.458.
F (x) =?
Questa è una funzione sigmoidea logistica:
Conosco x. Come posso calcolare F (x) in Python ora?
Diciamo x = 0.458.
F (x) =?
Risposte:
Questo dovrebbe farlo:
import math
def sigmoid(x):
return 1 / (1 + math.exp(-x))
E ora puoi provarlo chiamando:
>>> sigmoid(0.458)
0.61253961344091512
Aggiornamento : si noti che quanto sopra era principalmente inteso come una traduzione diretta one-to-one dell'espressione data in codice Python. È non testato o caratterizza per essere una corretta attuazione numericamente. Se sai di aver bisogno di un'implementazione molto solida, sono sicuro che ce ne sono altri in cui le persone hanno effettivamente pensato a questo problema.
math.exp
con np.exp
, non riceverai NaN, anche se riceverai avvisi di runtime.
math.exp
con matrice NumPy può produrre alcuni errori, come: TypeError: only length-1 arrays can be converted to Python scalars
. Per evitarlo dovresti usare numpy.exp
.
x = max(-709,x)
prima dell'espressione?
È disponibile anche in 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
che è solo un costoso wrapper (perché ti consente di ridimensionare e tradurre la funzione logistica) di un'altra funzione scipy:
In [3]: from scipy.special import expit
In [4]: expit(0.458)
Out[4]: 0.61253961344091512
Se sei preoccupato per le esibizioni continua a leggere, altrimenti usa solo 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
Come previsto logistic.cdf
è (molto) più lento di expit
. expit
è ancora più lento della sigmoid
funzione python quando viene chiamato con un singolo valore perché è una funzione universale scritta in C ( http://docs.scipy.org/doc/numpy/reference/ufuncs.html ) e quindi ha un overhead di chiamata. Questo sovraccarico è maggiore della velocità di calcolo expit
data dalla sua natura compilata quando viene chiamato con un singolo valore. Ma diventa trascurabile quando si tratta di grandi array:
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))
....:
(Noterai il piccolo cambiamento da math.exp
a np.exp
(il primo non supporta gli array, ma è molto più veloce se hai un solo valore da calcolare))
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
Ma quando hai davvero bisogno di prestazioni, una pratica comune è avere una tabella pre-calcolata della funzione sigmoid che si trova nella RAM e scambiare precisione e memoria per una certa velocità (ad esempio: http://radimrehurek.com/2013/09 / word2vec-in-python-part-two-optimizing / )
Inoltre, si noti che l' expit
implementazione è numericamente stabile dalla versione 0.14.0: https://github.com/scipy/scipy/issues/3385
Ecco come implementare il sigmoid logistico in modo numericamente stabile (come descritto qui ):
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)
O forse questo è più preciso:
import numpy as np
def sigmoid(x):
return math.exp(-np.logaddexp(0, -x))
Internamente, implementa le stesse condizioni di cui sopra, ma poi utilizza log1p
.
In generale, il sigmoide logistico multinomiale è:
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)))
max_q
e rebased_q
per tau
? perché l'ho provato e non ho probabilità che si
q
) per la tua temperatura. rebased_q può essere qualsiasi cosa: non cambia la risposta; migliora la stabilità numerica.
nat_to_exp
equivale a softmax (come hai già detto nella tua altra risposta)? Copia-incolla ne restituisce probabilità che non si sommano a 1
un altro modo
>>> def sigmoid(x):
... return 1 /(1+(math.e**-x))
...
>>> sigmoid(0.458)
pow
viene spesso implementato in termini di exp
e log
, quindi l'utilizzo exp
diretto è quasi sicuramente migliore.
x
è molto negativo.
Un altro modo trasformando la tanh
funzione:
sigmoid = lambda x: .5 * (math.tanh(.5 * x) + 1)
Penso che molti potrebbero essere interessati ai parametri gratuiti per alterare la forma della funzione sigmoide. Secondo per molte applicazioni, si desidera utilizzare una funzione sigmoid con mirroring. In terzo luogo, potresti voler eseguire una semplice normalizzazione, ad esempio i valori di output sono compresi tra 0 e 1.
Provare:
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
E per disegnare e confrontare:
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
Finalmente:
x = np.linspace(0,1,100)
Travel_function = draw_function_on_2x2_grid(x)
Buona risposta da @unwind. Tuttavia, non può gestire un numero estremamente negativo (lanciando OverflowError).
Il mio miglioramento:
def sigmoid(x):
try:
res = 1 / (1 + math.exp(-x))
except OverflowError:
res = 0.0
return res
Tensorflow include anche una sigmoid
funzione:
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
Una versione numericamente stabile della funzione sigmoidea logistica.
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)
Una fodera ...
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
o numpy array
:Le risposte migliori sono metodi ottimizzati per il calcolo a punto singolo, ma quando si desidera applicare questi metodi a una serie di panda o ad un array numpy, è necessario apply
, che è fondamentalmente per il ciclo in background e itererà su ogni riga e applicherà il metodo. Questo è abbastanza inefficiente.
Per accelerare il nostro codice, possiamo utilizzare la vettorializzazione e la trasmissione 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
O con un pandas Series
:
x = pd.Series(np.arange(-5,5))
np.divide(1, 1+np.exp(-x))
puoi calcolarlo come:
import math
def sigmoid(x):
return 1 / (1 + math.exp(-x))
o concettuale, più profondo e senza alcuna importazione:
def sigmoid(x):
return 1 / (1 + 2.718281828 ** -x)
oppure puoi usare numpy per le matrici:
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)
Il codice sopra è la funzione sigmoid logistica in python. Se io so che x = 0.467
, la funzione sigmoide, F(x) = 0.385
. Puoi provare a sostituire qualsiasi valore di x che conosci nel codice sopra e otterrai un valore diverso di F(x)
.
sigmoid = lambda x: 1 / (1 + math.exp(-x))