본문 바로가기
Book Review/[혼공머신] 리뷰

로지스틱 회귀

by 3n952 2023. 1. 4.

이번 포스팅에서는 로지스틱 회귀에 대해 혼공머신이 설명한 내용을 리뷰하도록 하겠습니다.


 

- Logistic regression(로지스틱 회귀)

로지스틱 회귀는 선형 회귀와 동일하게 선형 방정식을 학습합니다.

가령 식으로 표현하면, z = a * w + b * L + c * D + e와 같습니다. 

여기서 a, b, c는 각 가중치 혹은 계수가 되고 e는 편차 혹은 절편으로 상수값이 됩니다.

이 식은 다중 회귀의 선형 방정식과 같다고 볼 수 있습니다.

이때 z값을 확률로써 표현하기 위해 시그모이드 함수를 사용합니다.

식과 그래프는 다음과 같습니다.

 

시그모이드 함수 식

 

그림1) 시그모이드 함수(로지스틱 함수)

선형 방정식의 출력 z의 음수를 사용하여 자연 상수 거듭제곱하여 1을 더한 값의 역수를 취합니다.

이 함수 식은 딥러닝의 활성화 함수로도 자주 사용되니 알아두면 좋습니다.

 

그림 1은 시그모이드 혹은 로지스틱 함수의 그래프입니다.

시그모이드 함수에 z값이 들어가면 0~1 사이의 값을 가지게 됩니다. 이를 통해 계산 값들을 확률적으로 표현할 수 있게 됩니다.

z가 음수로 작아질수록 0의 값에 가까워지며, 양수로 커질수록 1의 값에 가까워집니다. (0% ~100%)

z가 0일때는 0.5가 됩니다.

 

이렇게 확률로써 나온 값들을 가지고 분류를 하게 됩니다. 따라서 로지스틱 회귀는 회귀모델이 아닌 분류모델입니다.

 

로지스틱 알고리즘을 정리하자면, 선형 방정식의 계수를 모델이 학습하고 그 값을 시그모이드 함수에 적용시켜 각 클래스에 대한

확률을 계산하는 것입니다. 가령 이진 분류문제에서 시그모이드 함수를 통과한 결과값이 0.5 이하면 '0'의 클래스로, 0.5 초과면 '1'의 클래스로 분류하는 식입니다.

 

로지스틱 회귀에 대해 이해를 했으니 실습코드로 다중분류를 해보겠습니다.

LogisticRegression클래스를 사용할 것입니다.

이 알고리즘은 반복적으로 수행되기 때문에 반복 횟수를 정해줘야 합니다.

또한 기본적으로 계수의 제곱을 규제합니다.(마치 릿지 회귀와 같습니다.)

이런 규제를 L2규제라고 합니다. 릿지에서는 알파를 규제 제어 매개변수로 사용했지만 

LogisticRegression에서는 규제를 제어하기 위해 C를 매개변수로 사용합니다.

알파와는 다르게 C는 작을수록 규제가 커지는 것을 의미합니다.

 

데이터는 혼공머신에서 제공하는 fish 데이터입니다.

코드는 다음과 같습니다.

#데이터 불러오기
import pandas as pd
fish = pd.read_csv('https://bit.ly/fish_csv_data') 

#입력 데이터, 정답 데이터 넘파이화
fish_input = fish[['Weight','Length','Diagonal','Height','Width']].to_numpy()
fish_target = fish['Species'].to_numpy()

#train/test split
from sklearn.model_selection import train_test_split
train_input, test_input, train_target, test_target = train_test_split(fish_input, fish_target, 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)

#로지스틱 회귀 모델 적용(규제 매개변수 C, 반복 횟수 1000)
lr = LogisticRegression(C=20, max_iter=1000)
lr.fit(train_scaled, train_target)

print(lr.score(train_scaled, train_target))
print(lr.score(test_scaled, test_target))

코드를 실행시켜 보면

훈련 셋, 테스트 셋에 대한 점수가 비슷한 것으로 보아 과대적합, 과소적합으로 치우쳐 보이진 않습니다.

그렇다면 이 분류 모델이 새로운 데이터에도 잘 예측을 하는지 테스트 셋의 처음 5개 샘플로 예측을 해보겠습니다.

 

#1~5번째 인덱스까지 예측 수행
print(lr.predict(test_scaled[:5]))

#각 인덱스별 확률 값
proba = lr.predict_proba(test_scaled[:5])

#확률값을 소수점 3자리로 반올림
print(np.round(proba, decimals=3))

클래스별 확률 출력

결과 값은 다음과 같이 나옵니다. 

5개의 샘플을 예측했으므로 5개의 행이 출력되었고, 7개의 클래스를 예측했으므로 7개의 열이 출력되었음을 확인할 수 있습니다.

 

예시로 첫 번째 샘플을 해석을 해보면 3번째 클래스일 확률이 가장 높으며 그 확률은 약 84.1%라는 것입니다.

이 세 번째 클래스가 무엇인지 확인하기 위해서는 classes_속성에서 확인하면 됩니다.

print(lr.classes_)

확인해보면 세번째 클래스는 'perch'입니다.
즉 첫 번째 샘플을 perch라고 예측하는 것입니다.

 

이를 보다 간편하고 효과적으로 적용하기 위해서는 소프트맥스(softmax) 함수를 사용해야 합니다.

로지스틱 함수는 하나의 선형 방정식에 대한 출력값을 0~1로 나타내어주지만, 

소프트맥스 함수는 여러 가지 선형 방정식에 대한 출력값을 0~1로 압축하고 총합이 1이 되게 합니다.

 

decision_function() 메서드로 z1~z7(7가지 선형 방정식에 대한 출력값)까지의 값을 구한 후

소프트맥스함수를 사용하여 확률로 표현해 보겠습니다.

코드는 다음과 같습니다.

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

실행 결과를 보면 이전의 predict_proba()의 배열과 일치하는 것을 확인할 수 있습니다.

 

 

이번 포스팅에서는 로지스틱 회귀에 대해 알아보았습니다.

정리하자면, 이진 분류에 대해서는 로지스틱 함수를 사용하고, 다중 분류에 대해서는 소프트맥스 함수를 사용하는 것이

유용하다는 것입니다.