Python'da bir lojistik sigmoid işlevi nasıl hesaplanır?


146

Bu bir lojistik sigmoid işlevidir:

resim açıklamasını buraya girin

Biliyorum x. Python'da şimdi nasıl F (x) hesaplayabilirim?

Diyelim x = 0.458.

F (x) =?

Yanıtlar:


219

Bunu yapmalı:

import math

def sigmoid(x):
  return 1 / (1 + math.exp(-x))

Ve şimdi arayarak test edebilirsiniz:

>>> sigmoid(0.458)
0.61253961344091512

Güncelleme : Yukarıdaki ifadenin temel olarak verilen ifadenin Python koduna doğrudan birebir çevirisi olarak tasarlandığını unutmayın. O edilir değil test veya sayısal olarak ses uygulaması olarak da bilinir. Çok sağlam bir uygulamaya ihtiyacınız olduğunu biliyorsanız, insanların gerçekten bu soruna biraz düşündükleri başkaları olduğuna eminim.


7
Sadece küçük şeyleri denemek için çok sık ihtiyacım olduğu için:sigmoid = lambda x: 1 / (1 + math.exp(-x))
Martin Thoma

2
Bu, x'in aşırı negatif değerleri için çalışmaz. NaN'ler yarattığını fark edene kadar bu talihsiz uygulamayı kullanıyordum.
Neil G

3
Eğer değiştirirseniz math.expile np.expAşağıdaki videoyu çalışma zamanı uyarıları alacak olsa, NaN'ler alamayacak.
Richard Rast

2
Kullanımı math.expgibi bazı hatalar verebilir numpy dizi: TypeError: only length-1 arrays can be converted to Python scalars. Bundan kaçınmak için kullanmalısınız numpy.exp.
ViniciusArruda

Sayısal istikrarsızlık x = max(-709,x), ifadeden önce eklenerek hafifletilebilir mi?
Elias Hasle

201

Scipy'de de mevcuttur: 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

bu da başka bir scipy fonksiyonunun sadece pahalı bir sarıcısıdır (çünkü lojistik fonksiyonunu ölçeklendirmenize ve çevirmenize izin verir):

In [3]: from scipy.special import expit

In [4]: expit(0.458)
Out[4]: 0.61253961344091512

Performanslar konusunda endişeleriniz varsa okumaya devam edin, aksi takdirde sadece kullanın expit.

Bazı kıyaslamalar:

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

Beklendiği gibi logistic.cdf(çok) daha yavaştır expit. C ile yazılmış evrensel bir işlev olduğu için tek bir değerle çağrıldığında expitpython sigmoidişlevinden hala daha yavaştır ( http://docs.scipy.org/doc/numpy/reference/ufuncs.html ) ile ve bu nedenle bir çağrı yükü vardır. Bu ek yük, expittek bir değerle çağrıldığında derlenmiş doğası tarafından verilen hesaplama hızından daha büyüktür . Ancak büyük diziler söz konusu olduğunda ihmal edilebilir hale gelir:

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))
   ....: 

(İle arasındaki küçük değişikliği fark edeceksiniz math.exp.np.exp ilki diziler desteklemez (ama çok daha hızlı bilgi işlem için yalnızca bir değer varsa olduğunu))

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

Ancak gerçekten performansa ihtiyacınız olduğunda, yaygın bir uygulama, RAM'de bulunan sigmoid işlevinin önceden hesaplanmış bir tablosuna sahip olmak ve bir miktar hassasiyet ve bellek alıp biraz hızlandırmaktır (örneğin: http://radimrehurek.com/2013/09 / word2vec-in-python-bölüm-iki en iyileştirme / )

Ayrıca, expituygulamanın 0.14.0 sürümünden beri sayısal olarak kararlı olduğunu unutmayın : https://github.com/scipy/scipy/issues/3385


4
Sigmoid işlevinizde ints (1) yerine
float

Ne demek istediğinizi anladığımdan emin değilim (örneklerde şamandıralar kullanılır), ancak her durumda, nadiren intergers üzerinde bir sigmoid hesaplar.
Théo T

2
Kd88'in söylediği, işlevinizde (1) kullandığınız sayısal değişmezlerin tamsayılar olarak ayrıştırılması ve çalışma zamanında yüzer hale getirilmesi gerektiğiydi. Kayan noktalı değişmez değerleri (1.0) kullanarak daha iyi performans elde edersiniz.
krs013

İşlevi istediğiniz zaman dizileri destekleyecek şekilde vektörleştirebilirsiniz.
agcala

pahalı bir paketleyici hakkında konuşmak ister misin? % timeit -r 1 çıkış (0.458)% timeit -r 1 1 / (1 + np.exp (0.458))
Andrew Louw

42

Lojistik sigmoidi sayısal olarak kararlı bir şekilde nasıl uygulayacağınız ( burada açıklandığı gibi ):

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)

Ya da belki de bu daha doğrudur:

import numpy as np

def sigmoid(x):  
    return math.exp(-np.logaddexp(0, -x))

Dahili olarak, yukarıdaki ile aynı koşulu uygular, ancak daha sonra kullanır log1p.

Genel olarak, çok terimli lojistik sigmoid:

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)))

(Ancak, logaddexp.reducedaha doğru olabilir.)


Ben de bir isteseydi multinomial lojistik sigmoid (SoftMax) atıfta bulunarak, Takviye öğrenme için sıcaklık parametresini , bu bölünmeden yeter mi max_qve rebased_qtarafından tau? çünkü bunu denedim ve 1
Ciprian Tomoiagă

@CiprianTomoiaga Bir sıcaklığa sahip olmak istiyorsanız, kanıtlarınızı ( q) sıcaklığınıza bölün . rebased_q herhangi bir şey olabilir: cevabı değiştirmez; sayısal kararlılığı artırır.
Neil G

nat_to_expsoftmax'a eşdeğer olduğundan emin misiniz (diğer cevabınızda belirttiğiniz gibi)? Kopyala-yapıştır, toplamı 1 olan olasılıkları döndürür
Ciprian Tomoiagă

@CiprianTomoiaga Kısa cevap, giriş ve çıktının son bileşenini atladığımdır, bu yüzden geri kalanının toplamı eksi olarak hesaplamak zorunda kalacaksınız. Daha istatistiksel açıklama, kategorik dağılımın n-1 doğal parametrelerine veya n-1 beklenti parametrelerine sahip olmasıdır.
Neil G

bir anlam ifade ediyor. Üzerinde ellaborate ister sorumu ?
Ciprian Tomoiagă

7

diğer yol

>>> def sigmoid(x):
...     return 1 /(1+(math.e**-x))
...
>>> sigmoid(0.458)

1
Bu ve çözülmenin işlevi arasındaki fark nedir? Math.e ** - x, math.exp (-x) 'den daha iyi midir?
Richard Knop

Çıktı sonucu açısından fark yoktur. Hız açısından farkı bilmek istiyorsanız, bunların yürütülmesini zamanlamak için timeit kullanabilirsiniz. Ama bu gerçekten önemli değil.
ghostdog74

9
powgenellikle doğrudan uygulanır expve logbu yüzden expdoğrudan kullanmak neredeyse kesinlikle daha iyidir.
japreiss

2
Bu xçok olumsuz olduğunda taşmalardan muzdariptir .
Neil G

7

tanhİşlevi dönüştürerek başka bir yol :

sigmoid = lambda x: .5 * (math.tanh(.5 * x) + 1)

@NeilG Matematiksel olarak sigmoid (x) == (1 + tanh (x / 2)) / 2. Sayısal olarak stabilize edilmiş yöntemler daha üstün olmasına rağmen, bu geçerli bir çözümdür.
scottclowe

6

Birçoğunun sigmoid fonksiyonunun şeklini değiştirmek için serbest parametrelerle ilgilenebileceğini hissediyorum. İkinci olarak birçok uygulama için yansıtılmış bir sigmoid işlevi kullanmak istiyorsunuz. Üçüncü olarak, basit bir normalleştirme yapmak isteyebilirsiniz, örneğin çıktı değerleri 0 ile 1 arasındadır.

Deneyin:

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

Ve çizmek ve karşılaştırmak için:

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

En sonunda:

x = np.linspace(0,1,100)
Travel_function = draw_function_on_2x2_grid(x)

Sigmoid fonksiyonlar grafiği


6

Sigmoid işlevinizin vektörleri ayrıştırmasına izin vermek için numpy paketini kullanın.

Derin Öğrenme ile uyumlu olarak, aşağıdaki kodu kullanıyorum:

import numpy as np
def sigmoid(x):
    s = 1/(1+np.exp(-x))
    return s

2

@ Unwind'dan iyi cevap. Ancak aşırı negatif sayıyı işleyemez (OverflowError atar).

Benim gelişimim:

def sigmoid(x):
    try:
        res = 1 / (1 + math.exp(-x))
    except OverflowError:
        res = 0.0
    return res

Bu daha iyidir, ancak yine de negatif değerlere sahip sayısal perküsyon sorunlarından muzdaripsiniz.
Neil G


2

Lojistik sigmoid fonksiyonunun sayısal olarak kararlı bir versiyonu.

    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)

1
x pozitifse sadece 1 / (1 + np.exp (-x)) kullanıyoruz, ancak x negatif olduğunda np.exp (x) / (1 + np.exp (x)) yerine kullanıyoruz. 1 / (1 + np.exp (-x)) kullanarak, x negatif olduğunda -x pozitif olur, bu nedenle np.exp (-x) büyük -x değeri nedeniyle patlayabilir.
Yash Khare

2

Bir astar ...

In[1]: import numpy as np

In[2]: sigmoid=lambda x: 1 / (1 + np.exp(-x))

In[3]: sigmoid(3)
Out[3]: 0.9525741268224334

1

pandas DataFrame/SeriesVeya kullanılırken vectorized yöntem numpy array:

En iyi yanıtlar, tek noktalı hesaplama için optimize edilmiş yöntemlerdir, ancak bu yöntemleri bir panda serisine veya numpy dizisine uygulamak istediğinizde, apply , temelde arka planda döngü için olan ve her satırda yinelenecek ve yöntemi uygulayacaktır. Bu oldukça verimsiz.

Kodumuzu hızlandırmak için vektörleştirme ve numpy yayınlardan yararlanabiliriz:

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

Veya aşağıdakilerle pandas Series:

x = pd.Series(np.arange(-5,5))
np.divide(1, 1+np.exp(-x))

1

şu şekilde hesaplayabilirsiniz:

import math
def sigmoid(x):
  return 1 / (1 + math.exp(-x))

veya kavramsal, daha derin ve herhangi bir ithalat olmadan:

def sigmoid(x):
  return 1 / (1 + 2.718281828 ** -x)

veya matrisler için numpy kullanabilirsiniz:

import numpy as np #make sure numpy is already installed
def sigmoid(x):
  return 1 / (1 + np.exp(-x))

0
import numpy as np

def sigmoid(x):
    s = 1 / (1 + np.exp(-x))
    return s

result = sigmoid(0.467)
print(result)

Yukarıdaki kod python'daki lojistik sigmoid fonksiyonudur. Bunu x = 0.467bilsem, Sigmoid fonksiyonu F(x) = 0.385. Yukarıdaki kodda bildiğiniz herhangi bir x değerini değiştirmeyi deneyebilirsiniz ve farklı bir değer elde edersiniz F(x).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.