파이썬에서 로지스틱 시그 모이 드 함수를 계산하는 방법은 무엇입니까?


145

이것은 로지스틱 S 자형 함수입니다.

여기에 이미지 설명을 입력하십시오

나는 x를 안다. 파이썬에서 F (x)를 어떻게 계산할 수 있습니까?

x = 0.458이라고합시다.

F (x) =?

답변:


218

이것은해야합니다 :

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

2
x의 극단적 음수 값에는 작동하지 않습니다. NaN을 생성 할 때까지이 불행한 구현을 사용하고있었습니다.
Neil G

3
당신이 교체하는 경우 math.expnp.exp당신은 런타임 경고를 얻을 것이다 있지만, NaN을을받지 않습니다.
Richard Rast

2
math.expnumpy 배열과 함께 사용하면 다음 과 같은 오류가 발생할 수 있습니다 TypeError: only length-1 arrays can be converted to Python scalars. 이를 피하려면을 사용해야합니다 numpy.exp.
ViniciusArruda

x = max(-709,x)표현식 앞에 추가하여 수치 적 불안정성을 완화 할 수 있습니까 ?
Elias Hasle 2019

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

이것은 다른 scipy 함수의 비용이 많이 드는 래퍼 일뿐입니다 (물류 함수를 확장하고 변환 할 수 있기 때문에).

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보다 (훨씬) 느립니다 expit. C ( http://docs.scipy.org/doc/numpy/reference/ufuncs.html )로 작성된 범용 함수 이므로 호출 오버 헤드 가 있기 때문에 단일 값으로 호출 할 때 expit여전히 파이썬 sigmoid함수 보다 속도가 느립니다 . 이 오버 헤드는 단일 값으로 호출 될 때 컴파일 된 특성으로 인한 계산 속도 향상보다 큽니다 . 그러나 큰 배열에 관해서는 무시할 수 있습니다.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

그러나 실제로 성능이 필요한 경우 일반적인 관행은 RAM에 저장되어있는 시그 모이 드 함수의 미리 계산 된 테이블을 가지고 약간의 속도와 정밀도 및 메모리를 교환하는 것입니다 (예 : http://radimrehurek.com/2013/09). / word2vec-in-python-part-two-optimizing / )

또한 expit버전 0.14.0부터 구현이 수치 적으로 안정적입니다. https://github.com/scipy/scipy/issues/3385


4
S 자형 함수에서 정수 (1) 대신 부동 소수점 (1)을 사용하면 실행 시간이 10 % 줄어 듭니다.
kd88

나는 당신이 무엇을 의미하는지 이해하지 못하지만 (예에서 부동 소수점이 사용됨) 어쨌든 interger에 대한 시그 모이 드를 거의 계산하지 않습니다.
Théo T

2
kd88이 말한 것은 함수 (1)에서 사용한 숫자 리터럴이 정수로 구문 분석되어 런타임에 부동 소수점으로 캐스팅되어야한다는 것입니다. 부동 소수점 리터럴 (1.0)을 사용하면 성능이 향상됩니다.
krs013

배열을 지원하도록 항상 함수를 벡터화 할 수 있습니다.
agcala

비싼 포장지에 대해 이야기하고 싶습니까? % timeit -r 1 expit (0.458) % timeit -r 1 1 / (1 + np.exp (0.458))
Andrew Louw

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_qrebased_q의해 tau? 내가 그것을 시도하고 1에 해당하는 확률을 얻을 수 없기 때문에
Ciprian Tomoiagă

@CiprianTomoiaga 온도를 유지하려면 증거 ( q)를 온도로 나눕니다 . rebased_q는 무엇이든 될 수 있습니다. 답을 바꾸지 않습니다. 수치 안정성을 향상시킵니다.
Neil G

당신이 확신은 nat_to_exp(당신이 당신의 다른 답변에서 언급 한)이 softmax에 해당? 그것의 복사-붙여 넣기는 1에 해당하지 않는 확률을 반환합니다
Ciprian Tomoiagă

@CiprianTomoiaga 짧은 대답은 입력과 출력의 최종 구성 요소를 생략한다는 것입니다. 따라서 나머지의 합계를 뺀 값으로 계산하려면 계산해야합니다. 보다 통계적인 설명은 범주 형 분포에 n-1 자연 모수 또는 n-1 기대 모수가 있다는 것입니다.
Neil G

말이됩니다. 내 질문에 대해 자세히 설명해 주 시겠습니까?
Ciprian Tomoiagă

7

또 다른 방법

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

1
이것과 unwind 기능의 차이점은 무엇입니까? math.e **-x가 math.exp (-x)보다 낫습니까?
Richard Knop

출력 결과는 차이가 없습니다. 속도 측면에서 차이를 알고 싶다면 timeit을 사용하여 실행 시간을 지정할 수 있습니다. 그러나 그것은 정말로 중요하지 않습니다.
ghostdog74

9
pow자주의 관점에서 구현 explog사용 때문에, exp직접하는 것은 거의 확실 좋습니다.
japreiss

2
이것은 x매우 음일 때 오버플로로 고통받습니다 .
Neil G

7

tanh함수 를 변환하여 다른 방법으로 :

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

@NeilG 수학적으로, 시그 모이 드 (x) == (1 + tanh (x / 2)) / 2. 수치 적으로 안정화 된 방법이 우수하지만 이것은 유효한 솔루션입니다.
scottclowe

6

나는 많은 사람들이 S 자형 함수의 모양을 바꾸는 자유 매개 변수에 관심이 있다고 생각합니다. 많은 애플리케이션에서 두 번째로 미러 된 시그 모이 드 기능을 사용하려고합니다. 셋째, 예를 들어 출력 값이 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)

S 자형 함수 그래프


6

numpy 패키지를 사용하여 S 자형 함수가 벡터를 구문 분석 할 수 있습니다.

Deeplearning에 따라 다음 코드를 사용합니다.

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

2

@unwind의 좋은 답변. 그러나 극단적 인 음수를 처리 할 수 ​​없습니다 (OverflowError 발생).

내 개선 :

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

이 방법이 더 좋지만 여전히 음수 값의 타악기 문제로 어려움을 겪고 있습니다.
Neil G


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)) 대신 np.exp (x) / (1 + np.exp (x)) 함수를 사용하는 것입니다 x가 음수 일 때 -x는 양수이므로 -x의 큰 값으로 인해 np.exp (-x)가 폭발 할 수 있기 때문에 1 / (1 + np.exp (-x)) 사용
Yash Khare

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:

상단 답변은 단일 포인트 계산에 최적화 된 방법이지만 이러한 방법을 팬더 시리즈 또는 numpy 배열에 적용하려면 apply기본적으로 백그라운드에서 루프 용이며 모든 행을 반복하여 적용합니다. 이것은 매우 비효율적입니다.

코드 속도를 높이기 위해 벡터화 및 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

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

또는 행렬에 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)

위의 코드는 파이썬의 로지스틱 S 자형 함수입니다. 내가 알면 x = 0.467, 시그 모이 드 함수 F(x) = 0.385. 위의 코드에서 아는 x 값을 대체하려고 시도하면 다른 값이 F(x)됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.