로지스틱 회귀
로지스틱 회귀
회귀이지만 분류 모델에서 사용한다. 왜 그런지에 대해서 검색해봤더니 위키 백과에서 그 이유를 어느정도 추측할 수 있었다.
로지스틱 회귀분석에서는 종속 변수가 이항분포를 따르는 모형을 사용하기 때문에 타겟 데이터를 범주형 데이터로 사용해야 하므로 로지스틱 회귀이지만 분류의 역할을 하게 되는것이라고 생각된다.
그렇다면 왜 로지스틱 분류가 아닌 회귀인가?
로지스틱 회귀는 선형 회귀처럼 독립 변수의 선형 결합으로 종속 변수를 설명하기 때문이다.
그러면 로지스틱 함수는 어떻게 정의되었는지 살펴보자
logistic(sigmoid) function
베르누이 시행에서 1이 나올 확률을 p 0이 나올 확률과 1-p라고 했을 때 이것의 비율을
\(odds=\frac{p}{1-p}\)
라고 하고 이것에 로그를 취하면 logit함수가 된다.
\(z=logit(odds)=log(\frac{p}{1-p})\)
이것의 역함수를 취해주면 로지스틱(시그모이드)함수가 된다 \(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}}\)
로지스틱 회귀
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확률을 보면 음성 클래스와 양성 클래스의 확률을 출력해준다.
decisions = lr.decision_function(train_bream_smelt[:5])
print(decisions)
LogisticRegression은 또한 decision값(z)값을 확인할 수있는데 이 값을 로지스틱 함수에 넣어 주면 확률값을 구할 수 있게 될 것이다.
from scipy.special import expit
print(expit(decisions))
SciPy 라이브러리에서 시그모이드함수를 가져와서 값을 넣어주면 양성클래스의 확률과 동일한 값을 출력한다.
로지스틱 회귀를 사용한 다중 분류
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개 샘플에 대한 예측을 출력해보면
print(lr.classes_)
몇 퍼센트의 확률로 해당 class를 예측했는지 알 수 있다.
print(lr.coef_.shape, lr.intercept_.shape)
coef와 intercept를 확인해보면 class가 7개이고 특성이 6개이기 때문에 아래와 같은 출력이 표시된다.
소프트맥스 함수
이진 분류가 아니기 때문에 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))
from scipy.special import softmax
proba = softmax(decision, axis=1)
print(np.round(proba, decimals=3))
SciPy 라이브러리에서 소프트맥스 함수를 가져와서 확인해 보면
이것을 위의 LogisticRegression의 pridict와 비교했을 때 같은 결과가 나오는 것을 확인할 수 있다.
참고
wikipedia,2022년 4월 13일 (수) 01:18 수정,2022년 5월 3일 접속, 로지스틱 함수 위키 링크
박해선,혼자 공부하는 머신러닝, 한빛미디어, 2021,183~196p