पायथन में एक लॉजिस्टिक सिग्मोइड फ़ंक्शन की गणना कैसे करें?


146

यह एक लॉजिस्टिक सिग्मोइड फ़ंक्शन है:

यहां छवि विवरण दर्ज करें

म x जानता हूं। अब मैं पायथन में एफ (एक्स) की गणना कैसे कर सकता हूं?

मान लीजिए कि x = 0.458 है।

F (x) =?

जवाबों:


219

यह करना चाहिए:

import math

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

और अब आप इसे कॉल करके जांच सकते हैं:

>>> sigmoid(0.458)
0.61253961344091512

अद्यतन : ध्यान दें कि उपरोक्त मुख्य रूप से पायथन कोड में दिए गए अभिव्यक्ति के सीधे एक-से-एक अनुवाद के रूप में था। यह एक संख्यात्मक ध्वनि कार्यान्वयन के लिए परीक्षण या ज्ञात नहीं है। यदि आप जानते हैं कि आपको बहुत मजबूत कार्यान्वयन की आवश्यकता है, तो मुझे यकीन है कि अन्य लोग भी हैं जहां लोगों ने वास्तव में इस समस्या को कुछ सोचा है।


7
सिर्फ इसलिए कि मुझे छोटी चीज़ों को आज़माने के लिए अक्सर इसकी आवश्यकता होती है:sigmoid = lambda x: 1 / (1 + math.exp(-x))
मार्टिन थोमा

2
यह एक्स के अत्यधिक नकारात्मक मूल्यों के लिए काम नहीं करता है। मैं इस दुर्भाग्यपूर्ण कार्यान्वयन का उपयोग कर रहा था जब तक मैंने देखा कि यह NaNs नहीं बना रहा था।
नील जी

3
यदि आप अपने math.expसाथ प्रतिस्थापित करते हैं np.expतो आपको NaN नहीं मिलेगा, हालाँकि आपको रनटाइम चेतावनियाँ मिलेंगी।
रिचर्ड रस्त

2
का उपयोग करते हुए math.expnumpy सरणी के साथ कुछ त्रुटियों की तरह, उपज कर सकते हैं: TypeError: only length-1 arrays can be converted to Python scalars। इससे बचने के लिए आपको उपयोग करना चाहिए numpy.exp
विनीसियस

क्या x = max(-709,x)अभिव्यक्ति के समक्ष जोड़कर संख्यात्मक अस्थिरता को कम किया जा सकता है ?
इलियास Hasle

201

यह 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

जो केवल एक महंगा रैपर है (क्योंकि यह आपको दूसरे स्कैपी फ़ंक्शन के पैमाने और लॉजिस्टिक फ़ंक्शन का अनुवाद करने की अनुमति देता है):

In [3]: from scipy.special import expit

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

यदि आप प्रदर्शन के बारे में चिंतित हैं तो पढ़ना जारी रखें, अन्यथा सिर्फ उपयोग करें 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

जैसा कि अपेक्षित logistic.cdfहै (बहुत) की तुलना में धीमा है expitexpitअभी भी अजगर sigmoidफ़ंक्शन की तुलना में धीमा है, जब इसे एकल मान के साथ कहा जाता है क्योंकि यह C ( http://docs.scipy.org/doc/numpy/reference/ufuncs.html ) में लिखा गया एक सार्वभौमिक कार्य है और इस तरह एक कॉल हेडहेड है। यह ओवरहेड expitएक एकल मूल्य के साथ बुलाए जाने पर अपने संकलित प्रकृति द्वारा दिए गए गणना गति से बड़ा है । लेकिन जब यह बड़े सरणियों में आता है तो यह नगण्य हो जाता है:

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

(आप से छोटे परिवर्तन दिखाई देगा math.expकरने के लिए np.exp(पहले एक सरणियों का समर्थन नहीं करता है, लेकिन बहुत तेजी से अगर आप गणना करने के लिए केवल एक मान हो है))

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

लेकिन जब आपको वास्तव में प्रदर्शन की आवश्यकता होती है, तो एक आम बात यह है कि सिग्मॉइड फ़ंक्शन की एक प्री-कॉम्प्लेक्स टेबल है जो रैम में है, और कुछ गति के लिए सटीक और मेमोरी का व्यापार करता है (उदाहरण के लिए: http://radimrehurek.com/2013/09) / word2vec-in-python-part-two-optimizing / )

यह भी ध्यान दें कि expitकार्यान्वयन 0.14.0 के बाद से संख्यात्मक रूप से स्थिर है: https://github.com/scipy/scipy/issues/3385



मुझे यकीन नहीं है कि मैं समझ सकता हूं कि आपका क्या मतलब है (उदाहरणों में फ़्लोट्स का उपयोग किया जाता है), लेकिन किसी भी मामले में शायद ही कोई अंतर पर एक सिग्मॉइड की गणना करता है।
थियो टी

2
Kd88 के कहने का अर्थ यह था कि आपके फ़ंक्शन (1) में उपयोग किए गए संख्यात्मक शाब्दिक शब्द पूर्णांक के रूप में हैं, और फ्लोट के लिए रनटाइम पर डाले जाने हैं। फ़्लोटिंग पॉइंट शाब्दिक (1.0) का उपयोग करके आपको बेहतर प्रदर्शन मिलेगा।
krs013

आप हमेशा फ़ंक्शन को वेक्टर कर सकते हैं ताकि यह सरणियों का समर्थन करे।
अगला

आप एक महंगी रैपर के बारे में बात करना चाहते हैं? % timeit -r 1 expit (0.458)% timeit -r 1 1 / (1 + np.exp (0.458))
एंड्रयू लौव

42

यहाँ बताया गया है कि आप सांकेतिक रूप से स्थिर तरीके से लॉजिस्टिक सिग्मॉइड को कैसे लागू करेंगे (जैसा यहाँ वर्णित है ):

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)

या शायद यह अधिक सटीक है:

import numpy as np

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

आंतरिक रूप से, यह ऊपर जैसी स्थिति को लागू करता है, लेकिन फिर उपयोग करता है log1p

सामान्य तौर पर, बहुराष्ट्रीय लॉजिस्टिक सिग्मोइड है:

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

(हालांकि, logaddexp.reduceअधिक सटीक हो सकता है।)


बहुपद रसद अवग्रह (softmax) की चर्चा करते हुए, अगर मैं भी एक चाहते थे सुदृढीकरण सीखने के लिए तापमान पैरामीटर , यह विभाजन करने के लिए पर्याप्त है max_qऔर rebased_qद्वारा tau? क्योंकि मैंने कोशिश की थी और मुझे संभावना नहीं है कि 1 को राशि
Ciprian Tomoiagă

@CiprianTomoiaga यदि आप एक तापमान रखना चाहते हैं, तो बस अपने सबूत ( q) को अपने तापमान से विभाजित करें । rebased_q कुछ भी हो सकता है: यह जवाब नहीं बदलता है; यह संख्यात्मक स्थिरता में सुधार करता है।
नील जी

क्या आप वाकई nat_to_expसॉफ्टमैक्स के बराबर हैं (जैसा कि आपने अपने अन्य उत्तर में उल्लेख किया है)? इसकी कॉपी-पेस्ट संभावनाएँ लौटाता है जो
सिप्रियन टोमोआगै

@CiprianTomoiaga संक्षिप्त उत्तर यह है कि मैं इनपुट और आउटपुट के अंतिम घटक को छोड़ देता हूं, इसलिए यदि आप इसे एक शेष राशि के रूप में चाहते हैं तो आपको इसकी गणना करनी होगी। अधिक सांख्यिकीय व्याख्या यह है कि श्रेणीबद्ध वितरण में n-1 प्राकृतिक पैरामीटर या n-1 अपेक्षा पैरामीटर हैं।
नील जी

समझ में आता है, की तरह। मेरे प्रश्न पर विस्तार से ध्यान दें ?
सिप्रियन टॉमोयागै

7

दूसरा रास्ता

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

1
इस और खोलना समारोह के बीच अंतर क्या है? क्या math.e ** - x, math.exp (-x) से बेहतर है?
रिचर्ड नॉप

आउटपुट परिणाम के मामले में कोई अंतर नहीं है। यदि आप गति के संदर्भ में अंतर जानना चाहते हैं, तो आप समय-समय पर उनके निष्पादन का उपयोग कर सकते हैं। लेकिन यह वास्तव में महत्वपूर्ण नहीं है।
भूतडोग ghost४

9
powअक्सर के मामले में लागू किया गया है expऔर log, इसलिए का उपयोग कर expसीधे लगभग निश्चित रूप से बेहतर है।
japreiss

2
यह xबहुत नकारात्मक होने पर ओवरफ्लो से पीड़ित होता है।
नील जी

7

tanhफ़ंक्शन को परिवर्तित करके दूसरा तरीका :

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

@NeilG गणितीय रूप से, सिग्मॉइड (x) == (1 + तन (x / 2)) / 2। तो यह एक वैध समाधान है, हालांकि संख्यात्मक रूप से स्थिर तरीके बेहतर हैं।
scottclowe

6

मुझे लगता है कि सिग्मॉइड फ़ंक्शन के आकार को बदलने के लिए कई को मुफ्त मापदंडों में रुचि हो सकती है। कई अनुप्रयोगों के लिए दूसरा जिसे आप मिरर किए गए सिग्मॉइड फ़ंक्शन का उपयोग करना चाहते हैं। तीसरा, आप एक सामान्य सामान्यीकरण करना चाहते हैं उदाहरण के लिए आउटपुट मान 0 और 1 के बीच हैं।

प्रयत्न:

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

और आकर्षित करने और तुलना करने के लिए:

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

आखिरकार:

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

सिग्मॉइड फ़ंक्शन ग्राफ़


6

अपने सिग्माइड फ़ंक्शन को पार्स वैक्टर को अनुमति देने के लिए खस्ता पैकेज का उपयोग करें।

Deeplearning के अनुरूप, मैं निम्नलिखित कोड का उपयोग करता हूं:

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

2

@Unwind से अच्छा जवाब। हालाँकि यह अत्यधिक नकारात्मक संख्या (अतिप्रवाह को फेंकना) को संभाल नहीं सकता है।

मेरा सुधार:

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

यह बेहतर है, लेकिन आप अभी भी नकारात्मक मूल्यों के साथ संख्यात्मक टक्कर मुद्दों से पीड़ित हैं।
नील जी


2

लॉजिस्टिक सिग्मोइड फ़ंक्शन का एक संख्यात्मक रूप से स्थिर संस्करण।

    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 धनात्मक है तो हम केवल 1 / (1 + np.exp (-x)) का उपयोग कर रहे हैं, लेकिन जब x ऋणात्मक होता है तो हम फ़ंक्शन np.exp (x) / (1 + np.exp (x)) का उपयोग कर रहे हैं बजाय 1 / (1 + np.exp (-x)) का उपयोग करना क्योंकि जब x ऋणात्मक -x धनात्मक होगा तो np.exp (-x) बड़े -x के मान के कारण विस्फोट हो सकता है।
यश खरे

2

एक लाइनर ...

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/Seriesया वेक्टर विधि numpy array:

शीर्ष उत्तर एकल बिंदु गणना के लिए अनुकूलित तरीके हैं, लेकिन जब आप इन तरीकों को पांडा श्रृंखला या संख्यात्मक सरणी में लागू करना चाहते हैं, तो इसके लिए आवश्यक है apply, जो मूल रूप से पृष्ठभूमि में लूप के लिए है और प्रत्येक पंक्ति पर पुनरावृति करेगा और विधि लागू करेगा। यह काफी अक्षम है।

हमारे कोड को गति देने के लिए, हम वैश्वीकरण और संख्यात्मक प्रसारण का उपयोग कर सकते हैं:

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

या एक के साथ pandas Series:

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

1

आप इसकी गणना इस प्रकार कर सकते हैं:

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

या वैचारिक, गहरा और बिना किसी आयात के:

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

या आप matrices के लिए numpy का उपयोग कर सकते हैं:

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)

उपरोक्त कोड पाइथन में लॉजिस्टिक सिग्मोइड फ़ंक्शन है। तो मैं जानता हूँ कि x = 0.467, अवग्रह समारोह, F(x) = 0.385। आप उपरोक्त कोड में आपके द्वारा ज्ञात किसी भी x का मान बदलने का प्रयास कर सकते हैं, और आपको एक अलग मान मिलेगा F(x)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.