[머신러닝] 로지스틱 회귀(logistic regression)
로지스틱 회귀(logistic regression)
로지스틱 회귀란?
로지스틱 회귀는 이름은 회귀이지만 분류 모델이다.
로지스틱 회귀는 선형 회귀와 마찬가지로 선형 방정식을 하지만 선형 회귀와 다르게 시그모이드 함수나 소프트맥스 함수를 사용하여 클래스를 예측한다.
로지스틱 회귀로 이진 분류 할 때는 시그모이드 함수를, 다중 분류 할 때는 소프트맥스 함수를 사용한다.
데이터 준비
데이터를 준비해 보자. 아래 링크 csv 파일을 사용한다.
https://bit.ly/fish_csv_data
import pandas as pd
#데이터 가져오기-------------------------------------------------------------------------
fish = pd.read_csv('https://bit.ly/fish_csv_data')
#입력 데이터 준비
fish_input = fish[['Weight','Length','Diagonal','Height','Width']].to_numpy()
print(fish_input)
#타깃 데이터 준비
fish_target = fish['Species'].to_numpy()
print(fish_target)
#훈련, 테스트 세트 나누기
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)
데이터 준비는 끝났다. 이제 이진 분류와 다중 분류를 해보자.
시그모이드 함수(sigmoid function)
시그모이드 함수는 x의 음수를 사용해 자연 상수 e를 거듭제곱하고 1을 더한 값의 역수를 취한다. 아래에 식을 참고 할것.
x가 무한하게 큰 음수 일수록 f(x)의 값은 0에 가까워지고,
x가 무한하게 큰 양수 일수록 f(x)의 값은 1에 가까워진다.
즉, f(x)는 x의 어떤 값이 들어오더라도 절대 0 ~ 1 사이의 범위를 벗어 날 수 없다.
위에 그래프는 시그모이드 함수의 출력이다. 그래프를 보면 x의 값이 - 6 부터 6까지 넣어도 f(x)는 0 ~ 1의 범위를 벗어 나지 않는다. 시그모이드 함수를 사용하여 이진 분류를 해보자.
이진 분류
우선 Bream과 Smelt를 골라내자.
불리언 인덱싱을 사용하여 Bream과 Smelt 데이터만 골라 낼 수 있다.
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]
모델 훈련
LogisticRegression 클래스를 사용하여 모델을 훈련 시키자.
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression()
lr.fit(train_bream_smelt, target_bream_smelt)
샘플 예측
5개 샘플만 예측해 보자.
print(lr.predict(train_bream_smelt[:5]))
<결과>
['Bream' 'Smelt' 'Bream' 'Bream' 'Bream']
5개가 예측된다.
샘플 예측 확률
예측한 5개의 샘플의 확률을 알아보자.
print(lr.predict_proba(train_bream_smelt[:5]))
<결과>
[[0.99759855 0.00240145]
[0.02735183 0.97264817]
[0.99486072 0.00513928]
[0.98584202 0.01415798]
[0.99767269 0.00232731]]
첫 번째 열이 음성 클래스(0)의 확률이고
두 번째 열이 양성 클래스(1)의 확률이다.
그렇다면 첫 번째 열과 두 번째 열 중 누가 bream이고 smelt 일까?
그렇다면 첫 번째 열과 두 번째 열 중 누가 bream이고 smelt 일까? 아래 예제를 입력하자.
print(lr.classes_)
<결과>
['Bream' 'Smelt']
Bream이 음성, smelt가 양성 클래스인 것을 확인 할 수 있다.
위에서 predict_proba 메서드가 반환한 값을 보면 확실히 두 번째 샘플만 두 번째 열의 확률이 높으므로 Smelt일 확률이 높다. 이진 분류가 정상적으로 수행 되었다.
소프트맥스 함수(softmax function)
로지스틱 회귀로 다중 분류 할 때는 소프트맥스 함수를 사용한다.
시그모이드 함수는 하나의 선형 방정식을 0 ~ 1의 값으로 압축 했다면 소프트맥스 함수는 여러 개의 선형 방정식을 0 ~ 1 사이로 압축하고 전체의 합이 1이 되도록 한다.
다중 분류
이진 분류는 단 2개의 샘플로만 분류를 했다면 다중 분류는 3개 이상의 샘플들을 분류 할 수 있다. 그러므로 csv의 데이터를 전부 사용하면 된다.
모델 훈련
모델 훈련은 이진 분류와 같다.
매개변수 C=20은 규제를 말한다. C가 낮을 수록 규제가 커진다.
max_iter=1000 은 반복 횟수를 말한다. 반복 횟수가 적다면 경고가 발생한다.
lr = LogisticRegression(C=20, max_iter=1000)
lr.fit(train_scaled, train_target)
샘플 예측 확률
상위 5개 샘플의 예측 확률을 보자.
#샘플 예측 확률
proba = lr.predict_proba(test_scaled[:5])
#네번째 자리 반올림
import numpy as np
print(np.round(proba, decimals=3))
<결과>
[[0. 0.014 0.841 0. 0.136 0.007 0.003]
[0. 0.003 0.044 0. 0.007 0.946 0. ]
[0. 0. 0.034 0.935 0.015 0.016 0. ]
[0.011 0.034 0.306 0.007 0.567 0. 0.076]
[0. 0. 0.904 0.002 0.089 0.002 0.001]]
첫 번째 샘플의 3번째 열을 보면 0.841로 가장 높다.(84.1%)
3번째 열이 뭔지 확인 해 보자
클래스 정보 확인
아까 설명 했듯 클래스 정보의 열의 순서가, 샘플 예측 확률 열의 순서와 같다. 즉, 0.841은 Perch의 데이터가 된다.
print(lr.classes_)
<결과>
['Bream' 'Parkki' 'Perch' 'Pike' 'Roach' 'Smelt' 'Whitefish']
전체 소스 코드
import pandas as pd
#데이터 가져오기-------------------------------------------------------------------------
fish = pd.read_csv('https://bit.ly/fish_csv_data')
#입력 데이터 준비
fish_input = fish[['Weight','Length','Diagonal','Height','Width']].to_numpy()
print(fish_input)
#타깃 데이터 준비
fish_target = fish['Species'].to_numpy()
print(fish_target)
#훈련, 테스트 세트 나누기
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)
#이진 분류----------------------------------------------------------------------------------
#Bream, smlet 데이터만 가져오기
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]
#모델 훈련
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression()
lr.fit(train_bream_smelt, target_bream_smelt)
#샘플 예측
print(lr.predict(train_bream_smelt[:5]))
#샘플 예측 확률
print(lr.predict_proba(train_bream_smelt[:5]))
print(lr.classes_)
#다중 분류----------------------------------------------------------------------------------
#모델 훈련
lr = LogisticRegression(C=20, max_iter=1000)
lr.fit(train_scaled, train_target)
#샘플 예측
print(lr.predict(test_scaled[:5]))
#샘플 예측 확률
proba = lr.predict_proba(test_scaled[:5])
#네번째 자리 반올림
import numpy as np
print(np.round(proba, decimals=3))
print(lr.classes_)
참조
혼자 공부하는 머신러닝 + 딥러닝(박해선, 한빛 미디어) : https://hongong.hanbit.co.kr/%ED%98%BC%EC%9E%90-%EA%B3%B5%EB%B6%80%ED%95%98%EB%8A%94-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EB%94%A5%EB%9F%AC%EB%8B%9D/
혼자 공부하는 머신러닝 + 딥러닝(깃 허브) : https://github.com/rickiepark/hg-mldl
댓글
댓글 쓰기