본문 바로가기
  • 문과생의 백엔드 개발자 성장기
|Playdata_study/AI

210809_MachinLearning 4 (Bagging /Boosting, 회귀- Linear Regression)

by 케리's 2021. 8. 9.

Random Forest 모델의 이점과 한계점 

 

 

Decision Tree 의 한계점

 

Decision Tree 는 Variance(분산)가 큰 모델이다.

 → overfitting 이 일어난다, 일반적인 학습이 이뤄지기 힘들다.

Input이 조금이라도 변하면 모델이 크게 변한다.

 

 

 

RandomForest가 이를 극복하는 방법

 

Decision Tree여러개를 결합하여 Variance(분산, 변동성) 을 낮춘다.

  → overfitting 을 현저히 줄였다. 대신 학습량도 많고 연산량도 늘려 속도가 늘어난다.

Tree처럼 outlier 값을 그대로 따라가지 않고 모함수와 더 비슷해지는 것을 볼 수 있다.

 

 

 

 

 

Bias VS Variance 

 

머신러닝 모델의 에러는 두가지로 분류 한다.

편향(Bias)과 분산(Variance) 이다.

두 개념은 서로 다르게 움직이는데 Bias를 해결하면 Variance가 올라가고 Variance를 해결하면 Bias가 올라간다.

이 현상을 "Bias - Variance Tradoff (편향- 분산 트레이드오프)" 라고 한다.

 

 

 

Bias 

 

Bias란 학습 데이터를 충분히 표현 할 수 없기 때문에 발생

높은 Bias를 보이는 모델은 underfitting이 된 상태

 

 

Variance

 

Variance란 트레이닝 데이터에 너무 민감하게 반응해서 발생

높은 Variance를 띄는 모델은 overfitting이 된 상태

 

 

 

 


 

 

 

 

앙상블(Ensemble)

여러개의 결정트리(Decision Tree)를 결합하여 하나의 결정 트리보다 더 좋은 성능을 내는 머신러닝 기법

학습법엔 두 가지로 나뉘는데 Bagging 과 Boosting 기법.

 

 

Bagging (Bootstrap Aggregation)

 

1) 부트 스트랩 (Bootstrap sampling)

현재있는 표본에서 추가적으로 표본 복원 추출하고 각 표본에 대한 통계랑을 다시 계산하는 절차방법 

 

 

즉, Bagging은 샘플을 여러 번 뽑아(Bootstrap) 각 모델을 학습시켜 결과를 집계(Aggregating) 하는 방법

 

 

추출된 표본들에 각각 모델(Decision Tree)을 적합시켜서 모델을 만들 수 있다.

각각의 예측결과를 합쳐 하나의 예측결과로 만들 수 있다.

: 하나의 트레이닝 샘플로부터 여러개의 샘플을 만든다, 각각의 샘플들을 학습

각각의 예측결과가 도출 그 값을 평균낸다.

 

 

Aggregating

 

Classification : 다수결

Regression : 평균

 

 

 

2) Bagging 의 문제점

 

모델이 전부 비슷하게 만들어지면 의미가 없어짐

 → random_state, max_feature 수를 조정하면 overffiting을 줄일 수 있다. 

 

강력한 설명 변수가 있다면 tree가 그 변수로 인해 대부분 비슷해진다.

→ 트리간에 강력한 상관관계가 생겨 이를 ensemble 해도 분산이 감소하지 않는다.

 

 

※ Bagging :: 하나의 트레이닝 샘플로 부터 여러개의 샘플을 만든다.

                 각각의 샘플들을 학습, 각각의 예측결과가 도출 그 값들을 평균낸다.

 

 

 

 

Boosting

 

가중치를 활용하여 약분류기를 강 분류기로 만드는 방법 

연속적인 weak learner, 바로직전 weak learner의 error를 반영한 현재 weak learner를 잡겠다는 아이디어

 

부스팅은 sequential 이 추가된다 (직행적) ↔ parallel (병행적)

- Bagging이 병렬로 학습하는 반면, Boosting은 순차적으로 학습시킴

학습이 끝나면 나온 결과에 따라 가중치가 재분배 

- Bagging이 일반적인 모델을 만드는데 집중되어있다면, Boosting은 맞추기 어려운문제를 맞추는데 초점이 맞춰있음

 

사용하긴 까다롭지만 성능이 가장 좋다 (지금까지 나온 모델중에서)

 

 

 

※ Boosting :: 하나의 트레이닝 모델이 있으면 그 모델을 학습시킨 결과로 예측값을 얻는다.

                   나온 예측값을 바탕으로 성능을 얻어낸다

                   오차(y-pred) =  Residual(잔차) , 오차가 점점 작아지는 방향으로 학습을 계속 진행 

                   오차를 바탕으로 기존의 특성값의 가중치를 재분배 

 

 

 

 

✔ Boosting Algorithm Implement

 

- learning_rate : 중요 매개 변수로 이전 트리의 오차를 얼마나 강하게 보정할 것인지 제어 

                      학습률이 크면 트리는 보정을 항하게 하기 때문에 복잡한 모델이 됨

                      n_estimators 값을 키우면 앙상블에 트리가 더 많이 추가되어 모델의 복잡도가 증가

 

 

 

 

1) GradientBoost 


   그래디언트 부스팅 결정트리는 지도학습에서 가장 강력하고 널리 사용하는 모델 중 하나이다.

   장점 : 특성의 스케일을 조정하지 않아도되고, 연속적인 특성에서 잘 동작함

   단점 : 매개변수 조정을 잘해야한다. 훈련시간이 길다. 트리기반 특성상 고차원 데이터에는 잘 작동하지 않음

 

 

 1-1) 매개변수

   n_estimators가 클수록 모델이 복잡해지고 과대 적합 될 가능성이 높아짐

   learning_rate를 낮추면 복잡도의 모델을 만들기 위해 더 많은 트리를 추가해야 함

   따라서 n_estimators를 맞추고 나서 적절한 learning_rate를 찾는 것이 좋다.

   max_depth : 보통 5보다 깊어지지 않게 사용

 

 

 

2) AdaBoost

 

 

 

 

 


실습

 

08_ML_GBM_cancer

 

 

1  GBM(Gradient Boosting Machin)

Boosting 알고리즘의 대표적인 모델에는 GradientBoosting 모델이 있다.
모델을 학습 - 예측하면서 오차(Residual) 를 구할 수 있고
도출된 오차를 기반으로 다시 기존 데이터 특징을 수정(가중치 재분배)하는 방식으로 학습을 전개한다.
이 때 가중치를 업데이트 하는 방법으로 경사하강법(Gradient Descent)을 이용한다.
경사하강법에 있어서는 학습 속도를 조절하는 learning_rate(0.01~0.004) 하이퍼 파라미터 값이 매우 중요한 매개변수가 된다.

 

 

from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import numpy as np
cancer = load_breast_cancer()
# cancer

 

 

1.1  split , Model Generator , Training, Predict, Accuracy Score

X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target)
# ----- 기본
gbm = GradientBoostingClassifier(random_state=0)

# 학습 
gbm.fit(X_train, y_train)

# predict 생략시 score함수로 사용하면 된다.
train_score = gbm.score(X_train, y_train) # train 성능확인
test_score = gbm.score(X_test, y_test)

# 훈련set 정확도 , test set 정확도 확인
print('훈련세트 정확도 : {:.3f}'.format(train_score))
print('테스트세트 정확도 : {:.3f}'.format(test_score))
# ---- 결과 

훈련세트 정확도 : 1.000
테스트세트 정확도 : 0.979

 

# ----- max_depth 사용
gbm = GradientBoostingClassifier(random_state=0, max_depth=1)

# 학습 
gbm.fit(X_train, y_train)
train_score = gbm.score(X_train, y_train) # train 성능확인
test_score = gbm.score(X_test, y_test)


# 훈련set 정확도 , test set 정확도 확인
print('훈련세트 정확도 : {:.3f}'.format(train_score))
print('테스트세트 정확도 : {:.3f}'.format(test_score))
# --- 결과 

훈련세트 정확도 : 0.995
테스트세트 정확도 : 0.965

 

 

# ---- learning_rate 사용
gbm = GradientBoostingClassifier(random_state=0, learning_rate=0.01)

# 학습 
gbm.fit(X_train, y_train)
train_score = gbm.score(X_train, y_train) # train 성능확인
test_score = gbm.score(X_test, y_test)

# 훈련 set 정확도 , test set 정확도 확인
print('훈련세트 정확도 : {:.3f}'.format(train_score))
print('테스트세트 정확도 : {:.3f}'.format(test_score))
# ----- 결과

훈련세트 정확도 : 0.986
테스트세트 정확도 : 0.951

 

 

2  특성 중요도 시각화하기

 

def plot_feature_importances(model):
    n_feature=cancer.data.shape[1]
    plt.barh(range(n_feature), model.feature_importances_, align='center')
    plt.yticks(np.arange(n_feature),cancer.feature_names)
    plt.xlabel("Feature Importaces")
    plt.ylabel("Feature")
    
plot_feature_importances(gbm)

# random 값으로 나옴

 

 

3  GridSearch Hyperparameter Tuning

그리드 서치를 이용한 하이퍼파라미터 튜닝

 

from sklearn.model_selection import GridSearchCV
## Boosting 에서 가장 많이 사용하는 하이퍼 파라미터들 
#   → learing_rate, max_depth, n_estimators

param_grid = {
    'n_estimators' : [100,150,200,250],
    'max_depth':[4,6,9,12],
    'learning_rate':[0.1,0.01,0.001] # 갯수 맞출필요 없음
    
}
### 우리가 적용할 모델을 설계

gmodel = GradientBoostingClassifier()
grid_search = GridSearchCV(gmodel,
                          param_grid = param_grid,
                          n_jobs = -1 # cpu 모두 사용하겠다.
                          )
grid_search.fit(X_train, y_train)
# ---- 결과

GridSearchCV(estimator=GradientBoostingClassifier(), n_jobs=-1,
             param_grid={'learning_rate': [0.1, 0.01, 0.001],
                         'max_depth': [4, 6, 9, 12],
                         'n_estimators': [100, 150, 200, 250]})

 

 

# GridSearchCV 최적 파라미터
grid_search.best_params_
# --- 결과

{'learning_rate': 0.001, 'max_depth': 6, 'n_estimators': 250}

 

# 위의 결과를 토대로 다시 학습 후 진행하기

model = GradientBoostingClassifier(random_state=0, learning_rate=0.001, max_depth=6, n_estimators=250)

model.fit(X_train, y_train)

train_score = model.score(X_train, y_train) # train 성능확인
test_score = model.score(X_test, y_test)

print('훈련세트 정확도 : {:.3f}'.format(train_score))
print('테스트세트 정확도 : {:.3f}'.format(test_score))
# ---- 결과

훈련세트 정확도 : 0.998
테스트세트 정확도 : 0.944

 

 


Regression (회귀)

 

회귀 분석에서는 Trainning Data에서 보여지듯 공부시간에 대한 값 입력에 대해서 결과값만 시험성적이 연속적인 반면, Classification 에서는 입력값은 회귀 분석과 동일한 값이지만 결과를 이상적인 분류값으로 나타내주고있다.

 

 

 

Logistic Regression 

선형으로 표현되지 않음, 연속적인 값 아님, 이진 분류값, multi 분류 

Classification 과 비슷하다

 

 

 

Linear Regression

 

  • 하나의 직선상에서 판결 되는 값, 연속적인 숫자 값 

Linear Regression 모델을만든다 = 선형회귀 방식으로 학습을 시킨다. 

Training DataSet을 학습시켜 예측을 가장 잘 할 수 있는 합리적인 직선을 찾아내는 것을 의미한다. 

 

    H(x) = w(기울기) X + B(절편)

 

합리적인 직선을 찾기 위해선 가설을 먼저 세운다.

가설을 수정해 가면서 합리적인 직선을 찾는 과정을 진행하며 이 과정을 '학습한다' 고 말한다. 

 

즉, 좌표에서 직선은 W(Weigth, 기울기) 와 b(bias, 절편)을 갖는 함수로 표현할 수 있다.

학습데이터를 잘 표현할 수 있는 W와 b를 잘 찾아내는 것이 학습의 목표이다.

 

 

  • 독립변수와 종속변수의 관계를 분석함

데이터의 분포 경향을 학습하여 새로운 데이터가 들어왔을 때 결과 값을 예측하는 것

결과 값이 연속적인 수로 나타난다. 

즉, 선형회귀는 독립변수 X를 이용해서 종속변수 Y를 예측하고 설명하는 작업을 말한다.

 

 

 

Cost Function

 

좋은 가설 : 실제값과 예상한 값의 거리가 짧을 수록 좋음

이 거리를 측정하는 것이 Cost(Loss) Function 이다. 

 * 성능지표 :: 분류 (갯수), 회귀 (거리)

 

 

즉, 실제값과 예측값 사이의 거리를 측정하는 것이 CostFuntion

이 값을 보면 우리가 세운 가설과 실제 데이터가 얼마나 일치하는지 알 수 있다.

가장 기본적인 값은 H(x) - y, 하지만 +혹은 - 값이 나올 수 있기 때문에 제곱을 한다.

 

 

* 제곱의 실제 이유

1) 양의 값만 도출

2) 예측이 잘못 되었을 때는 강한 패널티를 부여하기 위함이다. 

 

 

 

Cost(비용)는 가설이 얼마나 정확한지 판단하는 기준니다.

이 값이 적을 수록 0에 가까울수록 가설이 명확해 진다.

제곱의 이유 1) 오차를 양수로 리턴, 2) 패널티

Cost Funtion은 실제적으로 W와 b에 대한 Funtion이다.

Linear Regression의 목적은 가장 작은 Cost 값을 가지는 W와 b를 구하는 것이며 이것이 학습 목적이다.

 

 


 

 

실습

 

09_ML_Linear_MSE

 

1  Linear Regression이란?

 

딥러닝의 딥은 통계의 결과들이 무수히 얽혀있는 즉 연산들이 복잡하다는 뜻의 Deep이다.

이 연산중에서 가장 기본이 되는 연산이 바로 Linear Regression 선형회귀다. 

여기서는 과연 선형회귀가 어떤 것인지 차근차근 살펴보겠다

 

학생들과 성적의 관계 학생들마다 다 다양한 성적 분포를 가지는데 여기에 어떤 연관이 있는지 알아내고 그 연관 관계를 이용해서 결국에는 특정학생의 성적을 예측해보자.

 

학생들의 기말고사 성적은 [ ]에 따라 다르다

[ ]안에 시험성적을 좌우할 만한 요소들로 무엇이 있을까?

여기서 [ ]안에 들어갈 내용을 '정보'라 한다. 머신러닝과 딥러닝은 이 정보가 필요하다.

정보를 정확히 준비해 놓기만 하면 성적을 예측하는 방정식을 만들수 있다.

 

이것을 수학적으로 정의하면, 성적을 변하게 하는 '정보' 요소를 X라 하고, 이 값에 따라 변하는 '성적'을 Y라 한다.

'X값이 변함에 따라 Y값도 변한다'는 정의 안에서 독립적으로 변할 수 있는 값 X를 독립변수라 한다.

또한, 이 독립 변수에 따라 종속적으로 변하는 Y를 종속변수라 한다. 

선형회귀는 독립변수 X를 이용해서 종속변수 Y를 예측하고 설명하는 작업을 말한다.

 

 

1.1  예측선 그리기

 

기말고사를 준비하는 학생들을 대상으로 자료를 조사한 결과를 바탕으로 공부한 시간을 통해서 시험성적을 예측하자.
X = [2, 4, 6, 8] → 공부시간
Y = [81, 93, 91, 97] → 라벨

 

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import platform
from matplotlib import font_manager, rc
plt.rcParams['axes.unicode_minus'] = False

if platform.system() == 'Darwin':
    rc('font', family='AppleGothic')
elif platform.system() == 'Windows':
    path = "c:/Windows/Fonts/malgun.ttf"
    font_name = font_manager.FontProperties(fname=path).get_name()
    rc('font', family=font_name)
else:
    print('Unknown system!!')

 

X = [2,  4,  6,  8]  # 공부시간
Y = [81, 93, 91, 97] # 성적

plt.scatter(X,Y)
plt.xlabel('공부한시간')
plt.ylabel('기말고사성적')

plt.show()

 

왼쪽이 아래로 향하고 오른쪽이 위를 향하는 선형(직선으로 표시되는 형태의 그래프)을 보인다.

선형회귀는 이 점들의 특징을 가장 잘 나타내는 선을 그리는 과정이다.

여기서 선은 곧 일차함수 그래프이며 다음과 같은 공식으로 표현된다.
y = ax + b
여기서 x값은 독립변수이고 y값은 종속변수이다.

즉, x 값에 따라서 y값은 반드시 달라진다. 다만, 정확하게 계산하려면 상수 a와 b의 값을 알아야한다.

따라서 선형회귀문제는 결과적으로 a와 b값을 알아내는 문제이다.

 

 

1.2  최소제곱법

 

일차함수의 기울기 a와 절편 b를 구할수 있다

 

a = (x-x평균)(y-y평균)의 합 / (x-x평균)**의 합

b = y의 평균-(x의 평균x기울기a)

 

a = 2.3 b = 79

 

 

1.3  

y = 2.3x + 79

 

 

mx = np.mean(X) # x절편
my = np.mean(Y) # y절편

# 기울기의 분모에 해당하는 식을 알고리즘으로 표현
divisor = sum([(i-mx)**2 for i in X])


# 분자에 해당하는 부분
# x, y 의 편차를 곱해서 합한 값을 구한다.

# 벡터 
# a = ((X-mx)@(y-my)) / sum((X-mx)**2) 

def top(X, mx, Y, ym):
    d = 0
    for i in range(len(X)):
        d += (X[i] - mx) * (Y[i] - my)
    return d

divided = top(X, mx, Y, my)

a = divided / divisor
b = my-(mx*a)

print(a)
print(b
# 결과

2.3
79.0

 

## 위에서 나온 기울기와 절편값을 가지고 가설을 세우자 

X = np.array(X)
print(X)

Y = np.array(Y)
print(Y)

predict = a*X+b # 최적의 선형을 표현함 
predict
# ---- 결과

[2 4 6 8]
[81 93 91 97]
array([83.6, 88.2, 92.8, 97.4])

 

## 위에서 구한 a,b 를 가지고 만든 가설 선형을 그려보자

plt.scatter(X,Y)
plt.plot(X, predict, c='r')
plt.xlabel('공부한시간')
plt.ylabel('기말고사성적')

plt.show()

 

1.4  평균제곱 오차

 

 

1.4.1  평균제곱 오차가 작다는 것은 실제값과 예측값 사이의 간극이 크지 않다는 것을 말한다.

 

앞으로 딥러닝과 머신러닝을 공부할때 굉장히 많이 나오는 공식으로 이 값이 작으면 작을수록

예측한값의 정확도가 높아짐을 의미한다.

 

1.4.2  선형회귀란 임의의 직선을 그어서 이에 대한 평균제곱 오차를 구하고 이 값을 가장 작게 만들어주는 a와 b값을 찾아가는 작업이다.

 

def mse(y_hat, y): #y_hat = predict = a*X+b
    return((y_hat - y)**2).mean()
mse(predict, Y)
# ---- 결과

8.299999999999985

 

 

1.5  MSE (Mean Square Error   평균 제곱 오차) 실습하기

 

import numpy as np
data = [[2,81], [4,93],[6,91],[8,97]]
x = [i[0] for i in data]
y = [i[1] for i in data]
x
y
# ---- 결과 

[81, 93, 91, 97]

 

# 위 훈련 데이터를 가장 잘 표현 할 수 있는 선형의 직선을 찾아야한다. 가설을세워야한다 = a,b 를 찾는다.
# 임의로 a,b를 지정하고 예측해보자 -> cost가 나올것이다.

temp_a_b = [3, 76]
# 일차방정식 Y = aX + b 를 반환하는 함수 정의
def predict(x):
    return temp_a_b[0]*x + temp_a_b[1]
# 평균제곱근(MSE)공식을 그대로 파이썬 함수로 정의.
def mse(y_hat, y):
    return ((y_hat - y)**2).mean()
predict_result = [] # 예측값을 저장할 빈 리스트 생성
for i in range(len(x)): # x의 갯수만큼 for문 돌림, x값을 한번씩 i에 대입 
    predict_result.append(predict(x[i]))
    print("공부시간 = %d, 실제점수 = %d, 예측점수 = %d" %(x[i], y[i], predict(x[i])))
# ---- 결과 

공부시간 = 2, 실제점수 = 81, 예측점수 = 82
공부시간 = 4, 실제점수 = 93, 예측점수 = 88
공부시간 = 6, 실제점수 = 91, 예측점수 = 94
공부시간 = 8, 실제점수 = 97, 예측점수 = 100

 

# MSE() 함수에 값을 입력하여 최종값을 구하는 함수를 정의
def mse_val(predict_result, y): 
    return mse(np.array(predict_result), np.array(y))
print("MSE 최종값 : " + str(mse_val(predict_result, y)))
# ---- 결과

MSE 최종값 : 11.0

 

 

1.6  다음스텝

오차를 어떻게 줄여나가면서 학습을 계속할까? = 0에 가깝게 만듬
: 경사하강법 (Gradient Desent)

댓글