To jest logistyczna funkcja sigmoidalna:
Wiem x. Jak mogę teraz obliczyć F (x) w Pythonie?
Powiedzmy, że x = 0,458.
F (x) =?
To jest logistyczna funkcja sigmoidalna:
Wiem x. Jak mogę teraz obliczyć F (x) w Pythonie?
Powiedzmy, że x = 0,458.
F (x) =?
Odpowiedzi:
To powinno wystarczyć:
import math
def sigmoid(x):
return 1 / (1 + math.exp(-x))
A teraz możesz to przetestować dzwoniąc pod numer:
>>> sigmoid(0.458)
0.61253961344091512
Aktualizacja : Zwróć uwagę, że powyższe było głównie przeznaczone jako bezpośrednie tłumaczenie danego wyrażenia na kod Pythona. Nie została przetestowana ani nie jest znana jako poprawna numerycznie implementacja. Jeśli wiesz, że potrzebujesz bardzo solidnej implementacji, jestem pewien, że są inne osoby, w których ludzie zastanawiali się nad tym problemem.
math.exp
z np.exp
was nie dostanie Nans, chociaż dostaniesz ostrzeżenia uruchomieniowe.
math.exp
z numpy tablicy mogą dawać błędy, takie jak: TypeError: only length-1 arrays can be converted to Python scalars
. Aby tego uniknąć, powinieneś użyć numpy.exp
.
x = max(-709,x)
przed wyrażeniem?
Jest również dostępny w 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
który jest tylko kosztownym opakowaniem (ponieważ pozwala skalować i tłumaczyć funkcję logistyczną) innej funkcji scipy:
In [3]: from scipy.special import expit
In [4]: expit(0.458)
Out[4]: 0.61253961344091512
Jeśli obawiasz się występów, kontynuuj czytanie, w przeciwnym razie po prostu użyj 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
Zgodnie z oczekiwaniami logistic.cdf
jest (znacznie) wolniejszy niż expit
. expit
jest nadal wolniejszy niż sigmoid
funkcja Pythona, gdy jest wywoływana z pojedynczą wartością, ponieważ jest to uniwersalna funkcja napisana w języku C ( http://docs.scipy.org/doc/numpy/reference/ufuncs.html ) i dlatego ma narzut wywołania. Ten narzut jest większy niż przyspieszenie obliczeńexpit
z jego skompilowanej natury, gdy jest wywoływane z jedną wartością. Ale staje się pomijalny, jeśli chodzi o duże tablice:
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))
....:
(Zauważysz niewielką zmianę od math.exp
do np.exp
(pierwsza nie obsługuje tablic, ale jest znacznie szybsza, jeśli masz tylko jedną wartość do obliczenia))
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
Ale kiedy naprawdę potrzebujesz wydajności, powszechną praktyką jest posiadanie wstępnie obliczonej tabeli funkcji sigmoidalnej, która jest przechowywana w pamięci RAM i zamiana precyzji i pamięci na pewną prędkość (na przykład: http://radimrehurek.com/2013/09 / word2vec-in-python-part-two-optimizing / )
Zwróć również uwagę, że expit
implementacja jest stabilna numerycznie od wersji 0.14.0: https://github.com/scipy/scipy/issues/3385
Oto jak zaimplementowałbyś logistyczną sigmoidę w stabilny numerycznie sposób (jak opisano tutaj ):
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)
A może jest to dokładniejsze:
import numpy as np
def sigmoid(x):
return math.exp(-np.logaddexp(0, -x))
Wewnętrznie implementuje ten sam warunek co powyżej, ale potem używa log1p
.
Ogólnie rzecz biorąc, wielomianowa sigmoida logistyczna to:
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
i rebased_q
przez tau
? ponieważ próbowałem tego i nie dostaję prawdopodobieństwa, że suma
q
) przez swoją temperaturę. rebased_q może być wszystkim: nie zmienia odpowiedzi; poprawia stabilność numeryczną.
nat_to_exp
jest odpowiednikiem softmax (jak wspomniałeś w swojej drugiej odpowiedzi)? Kopiuj-wklej zwraca prawdopodobieństwa, które nie sumują się do 1
Inny sposób
>>> def sigmoid(x):
... return 1 /(1+(math.e**-x))
...
>>> sigmoid(0.458)
pow
jest często implementowany w kategoriach exp
i log
, więc używanie exp
bezpośrednio jest prawie na pewno lepsze.
x
jest bardzo ujemne.
Inny sposób poprzez przekształcenie tanh
funkcji:
sigmoid = lambda x: .5 * (math.tanh(.5 * x) + 1)
Wydaje mi się, że wielu mogłoby być zainteresowanych swobodnymi parametrami zmieniającymi kształt funkcji sigmoidalnej. Po drugie dla wielu aplikacji, w których chcesz użyć funkcji lustrzanej sigmoidy. Po trzecie, możesz chcieć wykonać prostą normalizację, na przykład wartości wyjściowe mieszczą się w zakresie od 0 do 1.
Próbować:
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
I narysować i porównać:
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
Wreszcie:
x = np.linspace(0,1,100)
Travel_function = draw_function_on_2x2_grid(x)
Dobra odpowiedź od @unwind. Nie radzi sobie jednak z ekstremalną liczbą ujemną (rzucając OverflowError).
Moja poprawa:
def sigmoid(x):
try:
res = 1 / (1 + math.exp(-x))
except OverflowError:
res = 0.0
return res
Tensorflow zawiera również sigmoid
funkcję:
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
Numerycznie stabilna wersja logistycznej funkcji sigmoidalnej.
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)
Jedna wkładka ...
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
lub numpy array
:Najlepsze odpowiedzi to zoptymalizowane metody obliczania pojedynczego punktu, ale jeśli chcesz zastosować te metody do serii pand lub tablicy numpy, wymaga to apply
, co w zasadzie dotyczy pętli w tle i będzie iterować po każdym wierszu i zastosować metodę. Jest to dość nieefektywne.
Aby przyspieszyć nasz kod, możemy wykorzystać wektoryzację i emisję 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
Lub z pandas Series
:
x = pd.Series(np.arange(-5,5))
np.divide(1, 1+np.exp(-x))
możesz to obliczyć jako:
import math
def sigmoid(x):
return 1 / (1 + math.exp(-x))
lub koncepcyjne, głębsze i bez importu:
def sigmoid(x):
return 1 / (1 + 2.718281828 ** -x)
lub możesz użyć numpy dla macierzy:
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)
Powyższy kod jest logistyczną funkcją sigmoidalną w Pythonie. Jeśli wiem, że x = 0.467
funkcja esicy, F(x) = 0.385
. Możesz spróbować podstawić dowolną wartość x, którą znasz w powyższym kodzie, a otrzymasz inną wartość F(x)
.
sigmoid = lambda x: 1 / (1 + math.exp(-x))