로지스틱 회귀
로지스틱 회귀
회귀이지만 분류 모델에서 사용한다. 왜 그런지에 대해서 검색해봤더니 위키 백과에서 그 이유를 어느정도 추측할 수 있었다.
로지스틱 회귀분석에서는 종속 변수가 이항분포를 따르는 모형을 사용하기 때문에 타겟 데이터를 범주형 데이터로 사용해야 하므로 로지스틱 회귀이지만 분류의 역할을 하게 되는것이라고 생각된다.
그렇다면 왜 로지스틱 분류가 아닌 회귀인가?
로지스틱 회귀는 선형 회귀처럼 독립 변수의 선형 결합으로 종속 변수를 설명하기 때문이다.
그러면 로지스틱 함수는 어떻게 정의되었는지 살펴보자
logistic(sigmoid) function
베르누이 시행에서 1이 나올 확률을 p 0이 나올 확률과 1-p라고 했을 때 이것의 비율을
\(odds=\frac{p}{1-p}\)
라고 하고 이것에 로그를 취하면 logit함수가 된다.
\(z=logit(odds)=log(\frac{p}{1-p})\)
/image-20220504000128498.png)
이것의 역함수를 취해주면 로지스틱(시그모이드)함수가 된다 \(p=log(\frac{z}{1-z}) \\ e^p=\frac{z}{1-z} \\ p=\frac{e^z}{1+e^z} \\ p=\frac{1}{1-e^{-z}} \\ \phi=\frac{1}{1+e^{-z}}\)
/KakaoTalk_20220502_212813819.jpg)
로지스틱 회귀
Fish Market 데이터를 사용해서 Species 제외한 다른 특성을 독립변수로 Species 중에서 Bream,Smelt를 타겟으로 하는 로지스틱 회귀 분석을 해 보자
y=df['Species']
X=df.drop(['Species'],axis=1)
from sklearn.model_selection import train_test_split
train_input, test_input, train_target, test_target = train_test_split(X, y, random_state=42)
데이터를 준비해 주고
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
ss.fit(train_input)
train_scaled = ss.transform(train_input)
test_scaled = ss.transform(test_input)
bream_smelt_indexes = (train_target == 'Bream') | (train_target == 'Smelt')
train_bream_smelt = train_scaled[bream_smelt_indexes]
target_bream_smelt = train_target[bream_smelt_indexes]
StandardScaler를 통해서 표준화를 한번 해 준 다음 Species중 Bream,Smelt 만 따로 뽑아준다.
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression()
lr.fit(train_bream_smelt, target_bream_smelt)
print(lr.predict_proba(train_bream_smelt[:5]))
LogisticRegression으로 훈련하고 테스트 5개 샘플의 predict확률을 보면 음성 클래스와 양성 클래스의 확률을 출력해준다.
/image-20220504073233557.png)
decisions = lr.decision_function(train_bream_smelt[:5])
print(decisions)
/image-20220504072816825.png)
LogisticRegression은 또한 decision값(z)값을 확인할 수있는데 이 값을 로지스틱 함수에 넣어 주면 확률값을 구할 수 있게 될 것이다.
from scipy.special import expit
print(expit(decisions))
SciPy 라이브러리에서 시그모이드함수를 가져와서 값을 넣어주면 양성클래스의 확률과 동일한 값을 출력한다.
/image-20220504073450977.png)
로지스틱 회귀를 사용한 다중 분류
LogisticRegression이 로지스틱 함수를 사용한 회귀를 한다는 것을 확인했으니 이제 Species 를 전부 사용해서 다중 분류를 해 보자
lr = LogisticRegression(C=20, max_iter=1000)
lr.fit(train_scaled, train_target)
로지스틱 회귀도 릿지 회귀처럼 L2규제를 사용하는데 위의 하이퍼파리미터 C는 릿지 회귀에서의 람다의 역수이다. 그러므로 값이 작을수록 규제가 강화된다.
proba = lr.predict_proba(test_scaled[:5])
print(np.round(proba, decimals=3))
5개 샘플에 대한 예측을 출력해보면
/image-20220504082403038.png)
print(lr.classes_)
/image-20220504082256845.png)
몇 퍼센트의 확률로 해당 class를 예측했는지 알 수 있다.
print(lr.coef_.shape, lr.intercept_.shape)
coef와 intercept를 확인해보면 class가 7개이고 특성이 6개이기 때문에 아래와 같은 출력이 표시된다.
/image-20220504083050842.png)
소프트맥스 함수
이진 분류가 아니기 때문에 softmax함수를 사용한다.
e값을 구할 때는 시그모이드가 p: 해당 확률 1-p:해당 확률이 아닌 것 으로 계산하였는데
다중 분류에서도 각각에 클래스에 해당 클래스의 확률p와 전체에서 해당 클래스를 뺀 확률 1-p를 사용하여 각각에 클래스에 대하여 시그모이드 함수값을 구한 다음 소프트맥스를 통해서 그 확률들의 합이 1이 되도록 해준다.
\[e_{sum}=e^{z1}+e^{z2}+e^{z3}+e^{z4}+e^{z5}+e^{z6}+e^{z7} \\ s_1=\frac{e^{z1}}{e_{sum}},\ s_2=\frac{e^{z2}}{e_{sum}} \ ,..., \ s_7=\frac{e^{z7}}{e_{sum}}\]각각의 z값을 구하면 아래와 같이 나오고
decision = lr.decision_function(test_scaled[:5])
print(np.round(decision, decimals=2))
/image-20220504084416728.png)
from scipy.special import softmax
proba = softmax(decision, axis=1)
print(np.round(proba, decimals=3))
SciPy 라이브러리에서 소프트맥스 함수를 가져와서 확인해 보면
/image-20220504084515429.png)
이것을 위의 LogisticRegression의 pridict와 비교했을 때 같은 결과가 나오는 것을 확인할 수 있다.
참고
wikipedia,2022년 4월 13일 (수) 01:18 수정,2022년 5월 3일 접속, 로지스틱 함수 위키 링크
박해선,혼자 공부하는 머신러닝, 한빛미디어, 2021,183~196p