혼자 공부하는 머신러닝+딥러닝 책을 바탕으로 공부한 내용입니다.
CH4 다양한 분류 알고리즘 ①
럭키백의 확률 계산하기
로지스틱 회귀 알고리즘을 배우고 이진 분류, 다중 분류 문제에서 클래스 확률을 예측해보자
한빛 마켓은 '럭키백(생선) 이벤트'를 하려고 한다.
럭키백은 구성품을 모른 채 먼저 구매하고, 배송받은 후에야 구성품을 알 수 있다.
럭키백에 포함된 생선의 확률을 알려주기 위해 로지스틱 회귀를 사용해보자
▶ 데이터 준비
import pandas as pd
fish = pd.read_csv("https://bit.ly/fish_csv_data")
fish.head()
어떤 종류의 생선이 있는지 판다스의 unique() 함수를 사용해 확인해보자
print(pd.unique(fish['Species']))
이 데이터 프레임에서 Species 열은 타깃 데이터, 나머지 5개 열은 입력 데이터로 사용하자
# 타깃 데이터
fish_target = fish['Species'].to_numpy()
# 입력 데이터
fish_input = fish[['Weight', 'Length', 'Diagonal', 'Height', 'Width']]
print(fish_input[:5])
- 타깃 데이터에 2개 이상의 클래스가 포함된 문제를 다중 분류라고 부른다.
이제 데이터를 train set, test set으로 나누고 표준화 전처리를 해주자
# train set, test set 나누기
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)
# train set, test set 표준화 전처리 하기
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
ss.fit(train_input)
train_scaled = ss.transform(train_input)
test_scaled = ss.transform(test_input)
▶ 로지스틱 회귀
로지스틱 회귀는 회귀 모델이 아닌 분류 모델이다.
선형 회귀처럼 계산한 값을 그대로 출력하는 것이 아니라 0-1 사이로 압축한다. (확률로 이해)
- 이진 분류일 경우
- 하나의 선형 방정식 훈련
- 방정식의 출력값을 시그모이드 함수에 통과시켜 0-1 사이의 값을 만든다.
- 0.5보다 크면 양성 클래스, 0.5보다 작으면 음성 클래스로 판단
- 다중 분류일 경우
- 클래스 개수만큼 방정식 훈련
- 방정식의 출력값을 소프트맥스 함수에 통과시켜 전체 클래스에 대한 합이 항상 1이 되도록 만든다.
시그모이드 함수를 그려보자
# 시그모이드 함수 그리기
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()
▶ 로지스틱 회귀로 이진 분류 수행하기
7개의 생선을 분류(다중 분류)해보기 전에 이진 분류(도미, 빙어)를 수행해보자
# 불리언 인덱싱
a = np.array(['A', 'B', 'C', 'D', 'E'])
print(a[[True, False, True, False, False]])
- 불리언 인덱싱을 이용하면 True, False 값으로 행을 선택할 수 있다.
이제, 훈련 세트에서 도미와 빙어에 해당하는 행만 골라보자
# 도미, 빙어 행만 골라내기
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)
훈련한 모델을 사용해 train_bream_smelt에 있는 처음 5개 샘플을 예측해보자
# 처음 5개 샘플 예측
print(lr.predict(train_bream_smelt[:5]))
- 두번째 샘플을 제외하고는 모두 Bream(도미)로 예측했다.
이번에는 predict_proba() 메서드를 통해 샘플의 예측 확률을 출력해보자
# 음성 클래스, 양성 클래스에 대한 확률
print(lr.predict_proba(train_bream_smelt[:5]))
- 첫번째 열은 음성 클래스(0)에 대한 확률, 두번째 열은 양성 클래스(1)에 대한 확률이다.
도미와 빙어 중 어떤 것이 양성 클래스인지 확인해보자
print(lr.classes_)
- 사이킷런은 타깃값을 알파벳순으로 정렬하여 사용한다.
- 빙어(Smelt)가 양성 클래스임을 확인할 수 있다.
로지스틱 회귀로 이진 분류를 해봤다.
선형 회귀에서 했던 것 처럼 로지스틱 회귀가 학습한 계수를 확인해보자.
# 로지스틱 회귀가 학습한 계수
print(lr.coef_, lr.intercept_)
- 이 로지스틱 회귀 모델이 학습한 방정식은 다음과 같습니다.
decision_function() 메서드는 양성 클래스에 대한 z 값을 반환한다.
반환 후 시그모이드 함수에 넣어보자
# 양성 클래스에 대한 z값 계산해보기
decision = lr.decision_function(train_bream_smelt[:5])
print(decision) #[-6.02927744 3.57123907 -5.26568906 -4.24321775 -6.0607117 ]
from scipy.special import expit
print(expit(decision))
- 출력된 값을 보면 predict_proba() 메서드 출력의 두번째 열의 값과 동일함을 확인할 수 있다
▶ 로지스틱 회귀로 다중 분류 수행하기
이제 LogisticRegression 클래스를 사용해 7개의 생선을 분류해보자
- 충분하게 훈련시키기 위해 반복 횟수를 1000으로 지정
- 규제를 제어하는 매개변수 C를 사용해 규제 완화
- LogisticRegression에서 규제를 제어하는 매개변수는 C이다.
- C는 alpha와 반대로 작을수록 규제가 커진다.
- C의 기본값은 1
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))
- train set, test set에 대해 점수가 높고 과대적합이나 과소적합으로 치우치지않았다.
테스트 세트의 처음 5개 데이터 샘플을 예측해보고 예측 확률을 구해보자
# test set의 처음 5개 샘플의 예측
print(lr.predict(test_scaled[:5]))
# 예측 확률
proba = lr.predict_proba(test_scaled[:5])
print(np.round(proba, decimals=3))
이제는 각 확률에 어떤 클래스에 대한 확률인지 확인해보자
print(lr.classes_)
- 첫번째 샘플은 Perch를 가장 높은 확률(84.1%)로 예측했다.
- 두번째 샘플은 Smelt를 가장 높은 확률(94.6%)로 예측했다.
이제 다중 분류일 경우 선형 방정식은 어떤 모습인지 확인해보자
# 선형 방정식 모습 확인하기
print(lr.coef_.shape, lr.intercept_.shape) #(7, 5) (7,)
- 다중 분류는 클래스마다 z값을 하나씩 계산한다.
- 7개의 z를 계산하고 소프트맥스 함수를 사용해 변환한다.
직접 decision_function() 메서드로 z1-z7까지의 값을 구한 뒤 소프트맥스 함수를 사용해 확률로 바꿔보자
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))
- axis를 지정하지 않으면 배열 전체에 대해 소프트맥스를 계산한다
- axis=1로 지정하면 각 행(샘플)에 대해 소프트맥스를 계산한다.
▶ 정리
- 로지스틱 회귀는 선형 방정식을 사용한 분류 알고리즘이다.
- 선형 회귀와 달리 시그모이드 함수나 소프트맥스 함수를 사용해 클래스 확률을 출력할 수 있다.
- 이진 분류일 경우
- 하나의 선형 방정식 훈련
- 방정식의 출력값을 시그모이드 함수에 통과시켜 0-1 사이의 값을 만든다.
- 0.5보다 크면 양성 클래스, 0.5보다 작으면 음성 클래스로 판단
- 다중 분류일 경우
- 클래스 개수만큼 방정식 훈련
- 방정식의 출력값을 소프트맥스 함수에 통과시켜 전체 클래스에 대한 합이 항상 1이 되도록 만든다.
'Python > ML & DL 공부' 카테고리의 다른 글
[ML] 05-1 결정 트리 (0) | 2022.03.11 |
---|---|
[ML] 04-2 확률적 경사 하강법 (0) | 2022.03.10 |
[ML] 03-3 특성 공학과 규제 (0) | 2022.03.07 |
[ML] 03-2 선형 회귀 (2) | 2022.03.06 |
[ML] 03-1 k-최근접 이웃 회귀 (0) | 2022.03.06 |