728x90

* 앙상블 학습 : 더 좋은 예측 결과를 만들기 위해 여러 개의 모델을 훈련하는 러신머닝 알고리즘

   - 정형 데이터를 다루는 데 가장 뛰어난 성과를 내고 있다. 대부분 결정 트리 기반

* 랜덤 포레스트 : 대표적인 결정 트리 기반 앙상블. bootstrap sample을 사용하고 랜덤하게 일부 특성을 선택하여 트리를 만드는 것이 특징

* 엑스트라 트리 : bootstrap sample을 만들지 않고 훈련 데이터를 사용. 대신 랜덤하게 노드를 분할해 과대적합을 감소

* 그레이디언트 부스팅 : 결정트리를 연속적으로 추가하여 손실 함수를 최소화. 훈련 속도가 느리지만 더 나은 성능을 기대할 수 있다. 이의 속도를 개선한 것이 히스토그램 기반 그레이디언트 부스팅이며 안정적인 결과와 높은 성능으로 인기

 

정형데이터 : 일정한 구조로 되어 있는 데이터 -> 앙상블 학습

비정형데이터 : 사진, 음악, 문학 등 일정하게 처리하기 어려운 데이터 -> 신경망 알고리즘

 

Random Forest

결정 트리를 랜덤하게 만들어 결정트리의 숲을 만든다.

bootstrap sample : train data에서 random으로 추출하여 sample을 만든다. 이 때 size는 train data와 같고, 중복 추출을 허용한다. -> train data가 1000개면 중복 추출 허용 방식으로 1000개를 뽑아 bootstrap sample을 만든다.

사이킷런의 random forest는 기본적으로 100개의 결정 트리를 훈련한 다음 각 트리의 클래스별 확률을 평균하여 가장 높은 확률을 가진 클래스를 예측으로 삼는다. (회귀일 때는 단순히 각 트리의 예측을 평균한다고 한다)

Extra Trees

random forest와 매우 비슷하게 동작. 기본 100개의 결정 트리를 훈련. parameter도 동일.

bootstrap sample 대신 전체 훈련 세트를 사용. 대신 노드를 분할할 때 랜덤으로 분할.(splitter='random')

성능이 떨어질 수 있으나 과대적합을 막는데 효과가 있다.

Gradient boosting

깊이 얕은 결정 트리를 사용하여 이전 트리의 오차를 보완하는 방식.

사이킷런의 GradientBoostingClassifier는 기본 깊이 3인 결정 트리 100개 사용.

깊이가 얕기 때문에 과대적합에 강함. 높은 일반화 성능 기대.

4장에서 다루었던 하강법을 사용하여 트리를 앙상블에 추가. 분류에서는 로지스틱 손실 함수를 사용하고 회귀에서는 평균 제곱 오차 함수 사용.

Histogram-based Gradient Boosting

입력 특성을 256개의 구간으로 나눈다. -> 노드를 분할할 때 최적의 분할을 빠르게 찾음

256개의 구간 중 하나를 떼어 놓고 누락된 값을 위해 사용한다. -> 누락된 특성이 있어도 이를 전처리 할 필요 없음

HistGradientBoostingClassifier는 트리 개수를 정하는데 n_estimators대신 부스팅 반복 횟수를 지정하는 max_iter를 사용. max_iter를 조정하여 성능을 조율.

 

사이킷런 외의 library

* XGBoost

* LightGBM

 

랜덤포레스트

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split

wine = pd.read_csv('https://bit.ly/wine_csv_data')

data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
target = wine['class'].to_numpy()

train_input, test_input, train_target, test_target = train_test_split(data, target, test_size=0.2, random_state=42)

from sklearn.model_selection import cross_validate
from sklearn.ensemble import RandomForestClassifier

rf = RandomForestClassifier(n_jobs=-1, random_state=42)
scores = cross_validate(rf, train_input, train_target, return_train_score=True, n_jobs=-1)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))

0.9973541965122431 0.8905151032797809

return_train_score의 기본값은 false : train socre를 같이 확인하면 과대적합을 파악하는데 용이.

훈련세트에 과대적합 되어 있다.

 

rf.fit(train_input, train_target)
print(rf.feature_importances_)

[0.23167441 0.50039841 0.26792718]

feature는 알코올 도수, 당도, pH순

5-1 결정트리에서는 아래와 같았다.

[0.12345626 0.86862934 0.0079144 ]
출처: https://bluelimn.tistory.com/entry/혼공머신-05-1-결정트리 [ANMIAN]

 

당도의 중요도가 내려가고 pH의 중요도가 높아졌다.

rf = RandomForestClassifier(oob_score=True, n_jobs=-1, random_state=42)

rf.fit(train_input, train_target)
print(rf.oob_score_)

0.8934000384837406

자체 알고리즘을 평가하는 기능이 있다. oob_score=True로 해주어야 한다.

엑스트라트리

from sklearn.ensemble import ExtraTreesClassifier

et = ExtraTreesClassifier(n_jobs=-1, random_state=42)
scores = cross_validate(et, train_input, train_target, return_train_score=True, n_jobs=-1)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))

0.9974503966084433 0.8887848893166506

et.fit(train_input, train_target)
print(et.feature_importances_)

[0.20183568 0.52242907 0.27573525]

그레이디언트 부스팅

from sklearn.ensemble import GradientBoostingClassifier

gb = GradientBoostingClassifier(random_state=42)
scores = cross_validate(gb, train_input, train_target, return_train_score=True, n_jobs=-1)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))

0.8881086892152563 0.8720430147331015

gb = GradientBoostingClassifier(n_estimators=500, learning_rate=0.2, random_state=42)
scores = cross_validate(gb, train_input, train_target, return_train_score=True, n_jobs=-1)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))

0.9464595437171814 0.8780082549788999

결정트리의 개수(default:100)를 500으로 늘려도 과대적합에 비교적 안전함

gb.fit(train_input, train_target)
print(gb.feature_importances_)

[0.15872278 0.68010884 0.16116839]

히스토그램 기반 부스팅

# 사이킷런 1.0 버전 아래에서는 다음 라인의 주석을 해제하고 실행하세요.
# from sklearn.experimental import enable_hist_gradient_boosting
from sklearn.ensemble import HistGradientBoostingClassifier

hgb = HistGradientBoostingClassifier(random_state=42)
scores = cross_validate(hgb, train_input, train_target, return_train_score=True, n_jobs=-1)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))

0.9321723946453317 0.8801241948619236

from sklearn.inspection import permutation_importance

hgb.fit(train_input, train_target)
result = permutation_importance(hgb, train_input, train_target, n_repeats=10,
                                random_state=42, n_jobs=-1)
print(result.importances_mean)

[0.08876275 0.23438522 0.08027708]

result = permutation_importance(hgb, test_input, test_target, n_repeats=10,
                                random_state=42, n_jobs=-1)
print(result.importances_mean)

[0.05969231 0.20238462 0.049 ]

hgb.score(test_input, test_target)

0.8723076923076923

XGBoost

from xgboost import XGBClassifier

xgb = XGBClassifier(tree_method='hist', random_state=42)
scores = cross_validate(xgb, train_input, train_target, return_train_score=True, n_jobs=-1)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))

0.8824322471423747 0.8726214185237284

LightGBM

from lightgbm import LGBMClassifier

lgb = LGBMClassifier(random_state=42)
scores = cross_validate(lgb, train_input, train_target, return_train_score=True, n_jobs=-1)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))

0.9338079582727165 0.8789710890649293

 

결정트리
[0.12345626 0.86862934 0.0079144 ]
Random Forest
[0.23167441 0.50039841 0.26792718]
Extra Trees
[0.20183568 0.52242907 0.27573525]
Gradient Boosting
[0.15872278 0.68010884 0.16116839]
Histogram-based Gradient Boosting
[0.08876275 0.23438522 0.08027708]

 

728x90
728x90

결정트리: yes/no로 구분하여 트리로 답을 찾는 알고리즘, 이해하기 쉽고 성능도 뛰어남

불순도: 결정트리가 최적의 질문을 찾기 위한 기준. sklearn은 gini불순도와 엔트로피 불순도를 제공

정보이득: 부도 노드와 자식 노드의 불순도 차이. 결정 트리 알고리즘은 정보 이득이 최대화 되도록 학습

  - 결정트리는 제한 없이 성장하면 훈련세트에 과대적합되기 쉬움.

  - 가지치기는 결정트리의 성장을 제한하는 방법

특성 중요도: 결정트리에 사용된 특성이 불순도를 감소하는데 기여한 정도

 

결정 트리

로지스틱 회귀로 와인 분류하기

import pandas as pd

wine = pd.read_csv('https://bit.ly/wine_csv_data')
wine.head()

wine.info()

 

info() 함수는 누락된 내용이 있는지 파악하는데 용이함

총 6497 entries중 non-null이 모두 6497이므로 누락된 내용은 없음

누락된 값이 있다면 그 data를 버리거나 평균 값으로 채워 넣어야 한다.

 

wine.describe()

describe()는 간단한 통계를 보여 준다.

data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
target = wine['class'].to_numpy()

from sklearn.model_selection import train_test_split

train_input, test_input, train_target, test_target = train_test_split(
    data, target, test_size=0.2, random_state=42)

print(train_input.shape, test_input.shape)

(5197, 3) (1300, 3)

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 LogisticRegression
lr = LogisticRegression()
lr.fit(train_scaled, train_target)

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

0.7808350971714451

0.7776923076923077

훈련세트(0.78), 테스트세트(0.77)로 과소적합

 

print(lr.coef_, lr.intercept_)

[[ 0.51270274 1.6733911 -0.68767781]] [1.81777902]

 

결정 트리

from sklearn.tree import DecisionTreeClassifier

dt = DecisionTreeClassifier(random_state=42)
dt.fit(train_scaled, train_target)

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

0.996921300750433

0.8592307692307692

로지스틱보다 나은 결과가 나왔지만 훈련세트가 0.99로 아주 높고 테스트세트가 0.85로 낮아 과대적합이다.

 

import matplotlib.pyplot as plt
from sklearn.tree import plot_tree

plt.figure(figsize=(10,7))
plot_tree(dt)
plt.show()

depth가 너무 깊어 과대적합이 되었다. 이를 제한하여 어떻게 결정되었는지 알아보자

plt.figure(figsize=(10,7))
plot_tree(dt, max_depth=1, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()

가지치기

dt = DecisionTreeClassifier(max_depth=3, random_state=42)
dt.fit(train_scaled, train_target)

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

0.8454877814123533

0.8415384615384616

max_depth를 5로 할 때 더 좋은 결과가 나왔는데 조건을 확인하기가 어려웠다

plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()

조건 식의 값들이 일반적으로 알기 어려운 숫자들이다. 이는 전처리를 거쳤기 때문으로 전처리 되지 않은 자료를 다시 넣고 결과를 확인해보자.

data에 대한 전처리가 필요하지 않다는 것이 결정 트리 알고리즘의 장점 중 하나

 

dt = DecisionTreeClassifier(max_depth=3, random_state=42)
dt.fit(train_input, train_target)

print(dt.score(train_input, train_target))
print(dt.score(test_input, test_target))

0.8454877814123533

0.8415384615384616

plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()

당도(sugar)가 4.325 이하, 1.625 이상이면서 alcohol이 11.025 이하면 red wine으로 인식하고 나머지는 white wine으로 인식

print(dt.feature_importances_)

[0.12345626 0.86862934 0.0079144 ]

 

728x90
728x90

확률적 경사 하강법, 손실 함수, 에포크

 

점진적 학습(온라인 학습)

 - 한번에 수많은 data를 모두 memory에 넣고 학습을 할 수 없으니 점진적으로 학습이 필요.

 - 또는 학습할 data가 시간이 지나면서 계속 추가되는 경우

 

확률적 경사 하강법 : Stochastic  Gradient Descent

 - 대표적인 점진적 학습 알고리즘

 - 훈련세트에서 하나씩 샘플을 꺼내 손실함수의 경사를 따라 최적의 모델을 찾는 알고리즘

미니배치 경사 하강법 : Minibatch Gradient Descent

 - 여러 개씩 꺼내 사용

배치 경사 하강법 : Batch Gradient Descent

 - 모두 꺼내 사용

점진적 학습 과정

손실함수: Loss Function, 비용 함수 : Cost Function

 - 손실 함수는 샘플 하나에 대한 손실을 정의, 비용 함수는 훈련 세트에 있는 모든 샘플에 대한 소실 함수의 합을 말하지만 엄격히 구분하지 않고 섞어 사용하는 경우가 많음

 - 확률적 경사 하강법이 최적화할 대상

 - 손실 함수는 오차가 얼마나 큰 지 측정하는 기준으로 함수의 값이 작을수록 좋다.

 - 손실 함수는 미분이 가능해야 한다

 

로지스틱 손실함수: Logistic Loss Function

이진 크로스엔트로비 손실 함수: Binary Cross-entropy Loss Function

크로스엔트로비 손실 함수: Cross-entropy Loss Function

 - 로지스틱 손실 함수를 사용하면 로지스틱 회귀 모델이 만들어진다.

 

회귀에서 사용하는 손실 함수:

평균 절댓값 오차

 - 타깃에서 예측을 뺀 절댓값을 모든 샘플에 평균한 값

평균 제곱 오차: Mean Squared Error

 - 타깃에서 예측을 뺀 값을 제곱한 다음 모든 샘플에 평균한 값

 

에포크

 - 확률적 경사 하강법에서 전체 샘플을 모두 사용하는 한 번 반복을 의미

 - 확률적 경사 하강법을 사용한 모델은 에프크 횟수에 따라 과소적합/과대적합이 될 수 있다.

 - 에포크가 너무 적으로면 과소, 많으면 과대 적합

 - 과대적합이 되기 전에 훈련을 멈추는 것이 조기종료(early stopping)

 

힌지 손실: hinge loss

 - SGDClassifier의 loss parameter의 기본 값, 서포트 백터 머신(Support vector machine) 알고리즘을 위한 손실 함수

 

SGDClassifier

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
sc = SGDClassifier(loss='log', max_iter=35, random_state=42)
sc.fit(train_scaled, train_target)

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

0.8403361344537815

0.8

sc.partial_fit(train_scaled, train_target)

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

0.907563025210084

0.925

에포크와 과대/과소적합

import numpy as np

sc = SGDClassifier(loss='log', random_state=42)

train_score = []
test_score = []

classes = np.unique(train_target)

# python에서 _ 변수는 다른 곳에서 사용하지는 않고 버리는 값을 저장하는데 쓴다
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()

sc = SGDClassifier(loss='log', 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

728x90
728x90

회귀(Regression) : class중 하로 분류하는 것이 아니라 임의의 어떤 숫자를 예측하는 문제

 

k-최근접 이웃 분류 Vs 회귀

분류 : 최근접 이웃 중에 가장 많은 class와 같은 것으로 분류

회귀 : 최근접 이웃의 평균으로 목표 숫자 예측

 

결정계수(R^2) : coefficient of determination

회귀 모델에서 예측의 적합도를 0과 1 사이의 값으로 계산, 1에 가까울수도 완벽

R^2 = 1 - (타깃 - 예측)^2 / (타깃 - 평균)^2

 

과대적합(Overfitting) Vs 과소적합(Underfitting)

과대적합은 훈련세트에 너무 심하게 맞춰져 있어 test점수가 낮아지는 현상

과소적합은 훈련세트에 제대로 맞지 않아 훈련세트/테스트세트 둘다 점수가 낮거나 심하면 테스트세트보다 훈련테스의 점수가 낮음

 

선형회귀 : Linear regression

직선을 학습하는 회귀 알고리즘

 

가중치(or 계수) : weight(or Coefficient)

선형 회귀가 학습한 직선의 기울기

 

다중 회귀 : Multiple regression

여러 개의 특성을 사용한 선형 회귀(다차원 그래프가 만들어진다)

 

transforemer(변환기)

사이킷런의 전처리용 class : 특성을 만들거나 target data없이 input data를 변환

 

릿지 회귀(Ridge regression)

규제가 있는 선형 회귀 모델 중 하나, alpha로 규제의 강도 조절, alpha가 클수록 규제 강도가 세짐(클수록 과대적합의 가능성 커짐)

라쏘회귀(Lasso regression)

릿지와 달리 계수 값을 아예 0으로 만들 수도 있음

 

Hyperparameter

머신러닝 모델이 학습할 수 없고 사람이 지정하는 파라미터

728x90

+ Recent posts