메이플의 개발 스토리
[ML] 4-1 로지스틱 회귀 본문
로지스틱 회귀¶
로지스틱 회귀¶
- rogistic regression
- 선형 방정식을 사용한 분류 알고리즘
- 선형 회귀와 달리 시그모이드 함수나 소프트맥스 함수를 사용하여 클래스 확률을 출력할 수 있음
다중 분류¶
- multi-class classification
- 타깃 클래스가 2개 이상인 분류 문제
- 로지스틱 회귀는 다중 분류를 위해 소프트맥스 함수를 사용하여 클래스를 예측함
시그모이드 함수¶
- sigmoid function(logistic function)
- 선형 방정식의 출력을 0과 1 사이의 값으로 압축하며 이진 분류를 위해 사용
소프트맥스 함수¶
- softmax
- 다중 분류에서 여러 선형 방정식의 출력 결과를 정규화하여 합이 1이 되도록 만듬
0. 데이터 준비¶
데이터 불러오기¶
In [ ]:
import pandas as pd
fish = pd.read_csv('https://bit.ly/fish_csv_data')
fish.head() # 처음 4개 행만 출력
Out[ ]:
Species | Weight | Length | Diagonal | Height | Width | |
---|---|---|---|---|---|---|
0 | Bream | 242.0 | 25.4 | 30.0 | 11.5200 | 4.0200 |
1 | Bream | 290.0 | 26.3 | 31.2 | 12.4800 | 4.3056 |
2 | Bream | 340.0 | 26.5 | 31.1 | 12.3778 | 4.6961 |
3 | Bream | 363.0 | 29.0 | 33.5 | 12.7300 | 4.4555 |
4 | Bream | 430.0 | 29.0 | 34.0 | 12.4440 | 5.1340 |
In [ ]:
print(pd.unique(fish['Species'])) # Species 열에서 고유한 값을 추출
['Bream' 'Roach' 'Whitefish' 'Parkki' 'Perch' 'Pike' 'Smelt']
In [ ]:
# 원하는 열을 선택해서 넘파이 배열로 변환
fish_input = fish[['Weight', 'Length', 'Diagonal', 'Height', 'Width']].to_numpy()
fish_target = fish['Species'].to_numpy()
print(fish_input[:5]) # 처음 5개 행만 출력
[[242. 25.4 30. 11.52 4.02 ] [290. 26.3 31.2 12.48 4.3056] [340. 26.5 31.1 12.3778 4.6961] [363. 29. 33.5 12.73 4.4555] [430. 29. 34. 12.444 5.134 ]]
훈련 세트와 테스트 세트 분리¶
In [ ]:
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)
표준화 전처리¶
In [ ]:
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
ss.fit(train_input)
train_scaled = ss.transform(train_input)
test_scaled = ss.transform(test_input)
1. k-최근접 이웃의 다중 분류¶
k-최근접 이웃 모델로 확률을 출력할 수 있지만 이웃한 샘플의 클래스 비율이므로 항상 정해진 비율만 출력한다.
In [ ]:
from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier(n_neighbors=3)
kn.fit(train_scaled, train_target)
print(kn.score(train_scaled, train_target))
print(kn.score(test_scaled, test_target))
0.8907563025210085 0.85
모델에 설정된 클래스 확인
In [ ]:
print(kn.classes_)
['Bream' 'Parkki' 'Perch' 'Pike' 'Roach' 'Smelt' 'Whitefish']
테스트 세트에 있는 처음 5개 샘플의 타깃값 예측
In [ ]:
print(kn.predict(test_scaled[:5]))
['Perch' 'Smelt' 'Pike' 'Perch' 'Perch']
클래스별 예측 확률값 확인
In [ ]:
import numpy as np
proba = kn.predict_proba(test_scaled[:5])
print(np.round(proba, decimals=4))
[[0. 0. 1. 0. 0. 0. 0. ] [0. 0. 0. 0. 0. 1. 0. ] [0. 0. 0. 1. 0. 0. 0. ] [0. 0. 0.6667 0. 0.3333 0. 0. ] [0. 0. 0.6667 0. 0.3333 0. 0. ]]
실제로 4번째 행이 위의 출력과 같은 확률이 되는지 최근접 이웃을 확인
In [ ]:
distances, indexes = kn.kneighbors(test_scaled[3:4])
print(train_target[indexes])
[['Roach' 'Perch' 'Perch']]
In [ ]:
print(test_scaled[3:4]) # 2차원 배열로 출력
print(test_scaled[3]) # 1차원 배열로 출력
[[-0.34698097 -0.23396068 -0.22320459 -0.11905019 -0.12233464]] [-0.34698097 -0.23396068 -0.22320459 -0.11905019 -0.12233464]
2. 로지스틱 회귀¶
- logistic regression
- 이름은 회귀이지만 분류 모델
- 선형 회귀와 동일하게 선형 방정식으로 학습
(예시 식) z = a X 무게 + b X 길이 + c X 대각선 + d X 높이 + e X 두께 + f
- a, b, c, d, e : 가중치 혹은 계수
- z는 어떤 값도 가능함. 하지만 확률이 되려면 0~1 사이의 값이 되어야 함 → 시그모이드 함수(로지스틱 함수)를 사용
ex) 시그모이드 함수를 그래프로 출력¶
- ∅ = 1 / (1 + e^-z)
In [ ]:
import numpy as np
import matplotlib.pyplot as plt
z = np.arange(-5, 5, 0.1)
phi = 1 / (1 + np.exp(-z))
plt.plot(z, phi)
plt.xlabel('z')
plt.ylabel('phi')
plt.show()
1) 로지스틱 회귀로 이진 분류 수행하기¶
ex) 불리언 인덱싱¶
In [ ]:
char_arr = np.array(['A', 'B', 'C', 'D', 'E'])
print(char_arr[[True, False, True, False, False]])
['A' 'C']
도미와 빙어 행만 골라내기¶
In [ ]:
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]
도미, 빙어 데이터로 로지스틱 회귀 모델 훈련¶
In [ ]:
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression()
lr.fit(train_bream_smelt, target_bream_smelt)
train_bream_smelt에 있는 처음 5개 샘플 예측¶
In [ ]:
print(lr.predict(train_bream_smelt[:5]))
['Bream' 'Smelt' 'Bream' 'Bream' 'Bream']
클래스와 예측 확률 출력¶
In [ ]:
print(lr.classes_)
print(lr.predict_proba(train_bream_smelt[:5]))
['Bream' 'Smelt'] [[0.99759855 0.00240145] [0.02735183 0.97264817] [0.99486072 0.00513928] [0.98584202 0.01415798] [0.99767269 0.00232731]]
cf) 계수 출력¶
z = -0.404 X 무게 + 0.576 X 길이 + 0.663 X 대각선 + 1.013 X 높이 + 0.732 X 두께 - 2.161
In [ ]:
print(lr.coef_, lr.intercept_)
[[-0.4037798 -0.57620209 -0.66280298 -1.01290277 -0.73168947]] [-2.16155132]
cf) 로지스틱 회귀 모델로 z 값 계산¶
In [ ]:
decisions = lr.decision_function(train_bream_smelt[:5])
print(decisions)
[-6.02927744 3.57123907 -5.26568906 -4.24321775 -6.0607117 ]
cf) 사이파이 라이브러리의 expit() 함수를 사용해 확률 계산¶
In [ ]:
from scipy.special import expit
print(expit(decisions))
2) 로지스틱 회귀로 다중 분류 수행하기¶
LogisticRegression 클래스로 다중 분류 모델을 훈련¶
- C 매개변수 : 규제의 양을 조절
- max_iter 매개변수 : 반복 횟수 지정 (기본 100)
In [ ]:
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))
0.9327731092436975 0.925
테스트 세트의 처음 5개 샘플에 대한 예측 출력¶
In [ ]:
print(lr.predict(test_scaled[:5]))
['Perch' 'Smelt' 'Pike' 'Roach' 'Perch']
예측 확률 출력¶
In [ ]:
proba = lr.predict_proba(test_scaled[:5])
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]]
cf) 클래스 정보 출력¶
In [ ]:
print(lr.classes_)
['Bream' 'Parkki' 'Perch' 'Pike' 'Roach' 'Smelt' 'Whitefish']
cf) coef_, intercept_의 크기 출력¶
In [ ]:
print(lr.coef_.shape, lr.intercept_.shape)
(7, 5) (7,)
intercept_가 7개 = z를 7개나 계산 = 클래스마다 z 값을 하나씩 계산
→ 이진 분류와 다르게 소프트맥스 함수를 사용하여 7개의 z 값을 확률로 변환
cf) z 값 계산¶
In [ ]:
decision = lr.decision_function(test_scaled[:5])
print(np.round(decision, decimals=2))
[[ -6.5 1.03 5.16 -2.73 3.34 0.33 -0.63] [-10.86 1.93 4.77 -2.4 2.98 7.84 -4.26] [ -4.34 -6.23 3.17 6.49 2.36 2.42 -3.87] [ -0.68 0.45 2.65 -1.19 3.26 -5.75 1.26] [ -6.4 -1.99 5.82 -0.11 3.5 -0.11 -0.71]]
cf) 사이파이 라이브러리에서 소프트맥스 함수를 통해 확률로 변환¶
In [ ]:
from scipy.special import softmax
proba = softmax(decision, axis=1)
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]]
'ML DL' 카테고리의 다른 글
[ML] 5-1 결정 트리 (0) | 2022.01.08 |
---|---|
[ML] 4-2 확률적 경사 하강법 (0) | 2022.01.08 |
[ML] 3-3 특성 공학과 규제 (0) | 2022.01.08 |
[ML] 3-2 선형 회귀 (0) | 2022.01.08 |
[ML] 3-1 K-최근접 이웃 회귀 (0) | 2022.01.08 |
Comments