GitHub - rickiepark/hg-mldl: <혼자 공부하는 머신러닝+딥러닝>의 코드 저장소입니다.
<혼자 공부하는 머신러닝+딥러닝>의 코드 저장소입니다. Contribute to rickiepark/hg-mldl development by creating an account on GitHub.
github.com
혼자 공부하는 머신러닝+딥러닝
이 책은 수식과 이론으로 중무장한 머신러닝, 딥러닝 책에 지친 ‘독학하는 입문자’가 ‘꼭 필요한 내용을 제대로’ 학습할 수 있도록 구성 되어 있습니다. 구글 머신러닝 전문가(Google ML expert)
www.youtube.com
Chapter 04
4-1. 로지스틱 회귀
- 다중 분류(multi-class classification) : 타깃 데이터에 2개 이상의 클래스가 포함된 문제
- 로지스틱 회귀(logistic regression) : 선형 방정식을 사용한 분류 알고리즘으로 선형 회귀와 달리 시그모이드 함수나 소프트맥스 함수를 사용하여 클래스 확률을 출력
- 시그모이드 함수/로지스틱 함수(sigmoid function/logistic regression) : 선형 방정식의 출력을 0과 1 사이의 값으로 압축하여 이진 분류를 위해 사용. 이진 분류일 경우 시그모이드 함수의 출력이 0.5보다 크면 양성 클래스, 0.5보다 작으면 음성 클래스로 판단
- 불리언 인덱싱(boolean indexing) : 넘파이 배열은 True, False 값을 전달하여 행을 선택할 수 있으며 이를 불리언 인덱싱이라고 함
- 소프트맥스 함수(softmax function) : 여러 개의 선형 방정식의 출력값을 0~1 사이로 압축하고 전체 합이 1이 되도록 만들며 이를 위해 지수 함수를 사용하기 때문에 정규화된 지수 함수라고도 함
- 데이터프레임(dataframe) : 판다스에서 제공하는 2차원 표 형식의 주요 데이터 구조
#데이터 준비하기
import pandas as pd
fish = pd.read_csv('https://bit.ly/fish_csv_data')
fish.head()
# Species 열애서 고유한 값 추출(unique() 함수 사용)
print(pd.unique(fish['Species']))
['Bream' 'Roach' 'Whitefish' 'Parkki' 'Perch' 'Pike' 'Smelt']
# 데이터프레임에서 입력 데이터로 사용할 열 선택
fish_input = fish[['Weight','Length','Diagonal','Height','Width']].to_numpy()
print(fish_input[:5])
데이터프레임에서 여러 열을 선택하면 새로운 데이터프레임이 반환됨. 이를 to_numpy() 메서드로 넘파이 배열로 바꾸어 fish_input에 저장.
# 타깃 데이터 만들기
fish_target = fish['Species'].to_numpy()
# 데이터를 훈련 세트와 테스트 세트로 나누기
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)
- k-최근접 이웃 분류기의 확률 예측
KNeighborsClassifier 클래스 객체 만들고 훈련 세트로 모델 훈련 후 점수 확인
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
타깃 값을 그대로 사이킷런 모델에 전달하면 순서가 자동으로 알파벳 순으로 매겨짐.
print(kn.classes_)
['Bream' 'Parkki' 'Perch' 'Pike' 'Roach' 'Smelt' 'Whitefish']
# 처음 5개 샘플의 타깃값 예측
print(kn.predict(test_scaled[:5]))
['Perch' 'Smelt' 'Pike' 'Perch' 'Perch']
predict_proba() 메서드로 클래스별 확률값 반환
import numpy as np
proba = kn.predict_proba(test_scaled[:5])
print(np.round(proba, decimals=4)) #소수점 4번째까지 표시 (5번째에서 반올림)
[[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. ]]
distances, indexes = kn.kneighbors(test_scaled[3:4])
print(train_target[indexes])
[['Roach' 'Perch' 'Perch']]
4 번째 샘플의 최근접 이웃의 클래스를 확인해보면 앞서 출력한 것과 확률이 일치하는 것을 확인할 수 있음
최근접 이웃으로 가능한 확률이 제한적임
- 로지스틱 회귀
시그모이드 함수 그리기
import numpy as np
import matplotlib.pyplot as plt
z = np.arange(-5, 5, 0.1) # -5 ~ 5 사이에 0.1 간격으로 배열 z 생성
phi = 1 / (1 + np.exp(-z)) # 지수 함수 계산 np.exp() 함수 사용
plt.plot(z, phi)
plt.xlabel('z')
plt.ylabel('phi')
plt.show()
- 로지스틱 회귀로 이진 분류 수행하기
불리언 인덱싱으로 도미와 빙어 데이터만 골라내기
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)
처음 5개 샘플 예측
print(lr.predict(train_bream_smelt[:5]))
['Bream' 'Smelt' 'Bream' 'Bream' 'Bream']
예측 확률 출력
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]]
속성 확인
print(lr.classes_)
로지스틱 회귀가 학습한 계수 확인
print(lr.coef_, lr.intercept_)
[[-0.4037798 -0.57620209 -0.66280298 -1.01290277 -0.73168947]] [-2.16155132]
# z값 출력
decisions = lr.decision_function(train_bream_smelt[:5])
print(decisions)
[-6.02927744 3.57123907 -5.26568906 -4.24321775 -6.0607117 ]
파이썬의 사이파이(scipy 라이브러리)의 expit() 함수 사용하면 분수 계산 하는 것보다 편리
from scipy.special import expit
print(expit(decisions))
[0.00240145 0.97264817 0.00513928 0.01415798 0.00232731]
- 로지스틱 회귀로 다중 분류 수행하기
lr = LogisticRegression(C=20, max_iter=1000) # 로지스틱 회귀에서 규제를 제어하는 매개변수 C(작을수록 규제 커짐)
lr.fit(train_scaled, train_target) # max_iter 반복횟수 지정
print(lr.score(train_scaled, train_target))
print(lr.score(test_scaled, test_target))
print(lr.predict(test_scaled[:5]))
['Perch' 'Smelt' 'Pike' 'Roach' 'Perch']
예측 확률 출력
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]]
클래스 정보 확인
print(lr.classes_)
['Bream' 'Parkki' 'Perch' 'Pike' 'Roach' 'Smelt' 'Whitefish']
크기 출력
print(lr.coef_.shape, lr.intercept_.shape)
(7, 5) (7,)
소프트맥스 함수
# z1 ~ z7 값 구하기
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]]
from scipy.special import softmax
proba = softmax(decision, axis=1) # 축 지정 : 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]]
위 proba 배열과 결과 일치 !
4-2. 확률적 경사 하강법
- 확률적 경사 하강법(stochastic gradient descent) : 훈련 세트에서 랜덤하게 하나의 샘플을 선택하여 손실 함수의 경사를 따라 최적의 모델을 찾는 알고리즘
- 에포크(epoch) : 확률적 경사 하강법에서 훈련 세트를 한 번 모두 사용하는 과정
- 미니배치 경사 하강법(minibatch gradient descent) : 1개가 아닌 여러 개의 샘플을 사용해 경사 하강법을 수행하는 방법으로 실전에서 많이 사용
- 배치 경사 하강법(batch gradient descent) : 한 번에 전체 샘플을 사용하는 방법, 컴퓨터 자원을 많이 사용
- 손실 함수(loss function) : 어떤 문제에서 머신러닝 알고리즘이 얼마나 엉터리인지를 측정하는 기준
- 로지스틱 손실 함수/이진 크로스엔트로피 손실 함수(logistic loss function) : 양성 클래스(타깃 = 1)일 때 손실은 -log(예측 확률)로 계산하며, 1 확률이 1에서 멀어질수록 손실은 아주 큰 양수가 됨. 음성 클래스(타깃 = 0)일 때 손실은 -log(1-예측 확률)로 계산함. 이 예측 확률이 0에서 멀어질수록 손실은 아주 큰 양수가 됨
- 크로스엔트로피 손실 함수(cross-entropy loss function) : 다중 분류에서 사용하는 손실 함수
- 힌지 손실(hinge loss) : 서포트 벡터 머신이라 불리는 또 다른 머신러닝 알고리즘을 위한 손실 함수로 널리 사용하는 머신러닝 알고리즘 중 하나. SGDClassifier가 여러 종류의 손실 함수를 loss 매개변수에 지정하여 다양한 머신러닝 알고리즘을 지원함
점진적 학습 -> 확률적 경사 하강법
SGDClassifer
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()
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)
from sklearn.linear_model import SGDClassifier
loss : 손실 함수 종류 지정 -> 로지스틱 손실 함수 log
max_iter : 수행할 에포크 횟수 지정
sc = SGDClassifier(loss='log', max_iter=10, random_state=42)
sc.fit(train_scaled, train_target)
print(sc.score(train_scaled, train_target))
print(sc.score(test_scaled, test_target))
0.773109243697479
0.775
정확도 낮음
# 모델 sc 추가 훈련 partial_fit() 메서드로
sc.partial_fit(train_scaled, train_target)
print(sc.score(train_scaled, train_target))
print(sc.score(test_scaled, test_target))
0.8151260504201681
0.85
에포크 훈련 더 할 필요 있음
에포크와 과대/과소적합
import numpy as np
sc = SGDClassifier(loss='log_loss', random_state=42)
train_score = []
test_score = []
classes = np.unique(train_target)
for _ in range(0, 300):
sc.partial_fit(train_scaled, train_target, classes=classes)
train_score.append(sc.score(train_scaled, train_target))
test_score.append(sc.score(test_scaled, test_target))
import matplotlib.pyplot as plt
plt.plot(train_score)
plt.plot(test_score)
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.show()
반복 횟수 100 적절 !
# 반복 횟수 100에 맞추고 모델 다시 훈련
sc = SGDClassifier(loss='log_loss', max_iter=100, tol=None, random_state=42)
sc.fit(train_scaled, train_target)
print(sc.score(train_scaled, train_target))
print(sc.score(test_scaled, test_target))
0.957983193277311
0.925
힌지 손실을 이용해 모델 훈련
sc = SGDClassifier(loss='hinge', max_iter=100, tol=None, random_state=42)
sc.fit(train_scaled, train_target)
print(sc.score(train_scaled, train_target))
print(sc.score(test_scaled, test_target))
0.9495798319327731
0.925
'혼공 ML+DL' 카테고리의 다른 글
5주차 Chapter 06 (비지도 학습) (0) | 2024.02.27 |
---|---|
4주차 Chapter 05 (트리 알고리즘) (0) | 2024.02.20 |
2주차 Chapter 03 (회귀 알고리즘과 모델 규제) (1) | 2024.02.06 |
1주차 Chapter 01 (나의 첫 머신러닝), Chapter 02 (데이터 다루기) (0) | 2024.01.31 |