5-1. 결정트리
<키워드 정리>
결정트리
: 예/아니오에 대한 질문을 이어나가면서 정답을 찾아 학습하는 알고리즘
불순도
: 결정 트리가 최적의 질문을 찾기 위한 기준
(지니 불순도 / 엔트로피 불순도)
정보 이득
: 부모 노드와 자식 노드의 불순도 차이
결정 트리 알고리즘 정보 이득이 최대화되도록 학습
특성 중요도
: 결정 트리에 사용된 특성이 불순도를 감소하는 데 기여한 정도
<상황>
캔 와인을 판매하려고 하는데
캔에 레드와인인지 화이트 와인인지 표시가 되어있지 않음
알코올 도수, 당도, pH 값으로 와인의 종류를 구별해보기
0) 로지스틱 회귀로 와인 분류하기
# 데이터 불러오기(6,497개의 와인 샘플)
import pandas as pd
wine = pd.read_csv('https://bit.ly/wine_csv_data')
# 처음 5개 샘플 확인
wine.head()
# class 0 레드와인 / 1 화이트 와인
# 데이터프레임의 각 열의 데이터 타입과 Null값 확인
wine.info()
# 데이터프레임 각 열에 대한 요약값
wine.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)
# test_size 지정해서 사이즈 바꿀 수 있음 (기본은 75:25)
print(train_input.shape, test_input.shape) >>> (5197, 3) (1300, 3)
# 결정트리는 scaler 필요없어
# StandardScaler 표준화
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)) >>> 0.7808350971714451
print(lr.score(test_scaled, test_target)) >>> 0.7776923076923077
# score 평가 점수 전반적으로 낮아...
print(lr.coef_, lr.intercept_) >>> [[ 0.51270274 1.6733911 -0.68767781]] [1.81777902]
❓로지스틱 회귀 모델 한계?
- 왜 저런 계수 값을 학습했는지 정확히 이해하기 어려움
- 숫자가 정확히 어떤 의미인지 설명하기 어려워
- 다항 특성 추가된다면 더욱 설명 어려움
=> 결정트리 사용
=> 이유를 설명하기 쉬워
1) 결정트리
- 어떤 값을 기준으로 스무고개처럼 질문을 던져 맞으면 왼쪽 틀리면 오른쪽
- from sklearn.tree import DecisionTreeCalssifier
- plot_tree 이용해서 결정 트리 그림 그리기
- from sklearn.tree import plot_tree
- 결정 트리 모델은 부모 노드와 자식 노드의 불순도 차이가 가능한 크도록 만든다
- 정보이득이 최대가 되도록 만든다
장점
- 결과를 누구에게나 설명하기 용이함
- 표준화 전처리 과정 필요 없음(특성값의 스케일 결정 트리 알고리즘에 영향을 미치지 않음)
🔎 결정 나무의 구성요소
ㆍ노드(하나의 클래스가 갖고 있는 정보)
- 루트노드(root) : 맨 꼭대기에 있는 노드
- 리프노드(leaf) : 맨 마지막 줄에 해당하는 노드
ㆍ 가지(branch) : 테스트의 결과(True, False)를 나타냄(일반적으로 하나의 노드 2개의 가지)
ㆍ 깊이(Depth) : 루트노드부터 끝노드까지의 중간노드들의 수
# plot_tress sklearn이 제공해줘
# matplotlib 불러온 이유 시각화에 대한 기본 환경 설정과 그래프 보여주기 위해 불러왔어
import matplotlib.pyplot as plt
from sklearn.tree import plot_tree
plt.figure(figsize=(10,7))
plot_tree(dt)
plt.show()
🔎 가지치기 (max_depth = )
- plot_tree() 함수에서 매개변수 값 조정
-
ㆍ 가지?
# 가지치기 전체 트리에서 일부분만 뽑아내
#루트노드는 0 depth
# 루트노드는 depth에서 제외 당연히 보여줘
plt.figure(figsize=(10,7))
plot_tree(dt, max_depth=1, filled=True, feature_names=['alcohol','sugar','pH'])
# max_depth 루트노드를 제외하고 하나의 노드를 더 확장하여 그림
# filled 노드의 색 칠해
# feature_names 특성의 이름 전달 (안쓰면 임의의 변수로)
plt.show()
🔎 불순도
ㆍ지니불순도
DecisionTreeClassifier 클래스에서 criterion 매개변수 기본값 'gini'
= 1 - ( 음성 클래스 비율^2 + 양성 클래스 비율^2 )
1 - ( (!258/5197)^2 + (3939 / 5197)^2) = 0.367
- 지니계수가 0이 된 노드 순수노드
- 노드에 하나의 클래스만 있다면 지니 불순도는 0이 됨
ㆍ엔트로피
DecisionTreeClassifier 클래스에서 criterian='entropy'를 지정
둘 다 노드의 클래스 비율을 사용하지만 차이점 제곱이 아니라 밑이 2인 로그를 사용하여 곱함
정보이득 맨꼭대기와 바로 밑에 부모와 자식사이ㅡ의 관계
가지치기
특성중요도
결정트리 어느 특성이 가장 중요한지
가장 중요한 특성을 sugar라고 생각한 거야
맨 처음 테스트 조건(sugar)
gini 불순물 (0이면 판단이 완벽하게 끝난 부분 => value값이 한쪽으로 쏠려)
samples = 총 샘플 수
value = 클래스별 샘플 수 ex([81, 2194] 인덱스0번 레드 / 1번 화이트
불순도
ㆍ지니불순도 = 1 - ( 음성 클래스 비율^2 + 양성 클래스 비율^2 )
1 - ( (!258/5197)^2 + (3939 / 5197)^2) = 0.367
지니계수가 0이 된 노드 순수노드
노드에 하나의 클래스만 있다면 지니 불순도는 0이 됨
결정 트리 모델은 부모 노드와 자식 노드의 불순도 차이가 가능한 크도록 만든다
부모와 자식 노드 사이의 불순도 차이를 정보 이득
정보이득이 최대가 되도록 만든다
ㆍ엔트로피
둘 다 노드의 클래스 비율을 사용하지만 차이점 제곱이 아니라 밑이 2인 로그를 사용하여 곱함
결정트리
가지치기
max_depth 최대 어디까지의 트리를 만들어달라
스무고개 트리처럼 sugar로 질문하다가 더이상 이걸로 안되겠다 다음 특성 pH로 질문...
리프
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))
# 가장 최적화된 max_depth 찾아줘야해... => 자동으로 찾아주는 것 hyper
plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol','sugar','pH'])
plt.show()
결정 트리 쪽에서는 스칼라 사용 안하는 것이 좋아
스칼라 사용하지 않으면 값이 직관적으로 보여주기 때문에 판단하기 좋아
결정트리 특성 중요도
뎁스값 바꿔주고 파라미터값 바꿔서 실행하기 귀찮아
search 통해서
하이퍼파라미터 최적화의 값 찾아주는 거 두 가지
- 그리드 서치
- 랜덤 서치
5-2. 교차검증과 그리드 서치
<키워드 정리>
검증세트
: 하이퍼파라미터 튜닝을 위해 모델을 평가할 때,
테스트 세트를 사용하지 않기 위해 훈련세트에서 다시 떼어낸 데이터 세트
교차검증
: 훈련 세트를 여러 폴드로 나눈 다음 한 폴드가 검증 세트의 역할을 하고 나머지 폴드에서는 모델을 훈련
이런 식으로 모든 폴드에 대한 검증 점수를 얻어 평균하는 방법
그리드 서치
: 하이퍼파라미터 탐색을 자동화해 주는 도구
탐색할 때 매개변수를 나열하면 교차 검증을 수행하여 가장 좋은 검증 점수의 매개변수 조합을 선택함
마지막으로 이 매개변수 조합으로 최종 모델을 훈련
랜덤 서치
: 연속된 매개변수 값을 탐색할 때 유용
탐색 값을 샘플링할 수 있는 확률 분포 객체를 전달(탐색할 값 직접 나열 x)
지정된 횟수만큼 샘플링하여 교차 검증을 수행하기 때문에 시스템 자원이 허락하는 만큼 탐색량을 조절할 수 있음
❓ 테스트 세트를 사용해 계속 성능 확인 => 점점 테스트 세트에 맞춰지는 것...?
=> 테스트 세트는 마지막에 딱 한 번만 사용하자
=> 훈련세트, 검증세트, 테스트 세트로 구분
💡 교차검증
- 검증 세트를 떼어 평가하는 과정을 여러 번 반복하여 검증 점수의 평균 값을 얻음
- 주로 5~10 폴드 교차 점증을 사용 (기본값 5 폴드 검증)
- 사이킷런에 cross_validate() 함수 사용
from sklearn.model_selection import cross_validate
🔎 검증 세트
- 훈련 세트를 쪼개서 검증 세트를 만들어
- 보통 20~30% 테스트 세트와 검증 세트로 떼어 놓음
Cross Validation
cross_validate(모델명, 데이터)
첫 번째 값 무조건 모델명 들어와야 해
교차검증 기본값 5
폴드
훈련세트를 몇 부분으로 나누냐
결과값 딕셔너리로 만들어짐
훈련시간(컴퓨터마다 달라)
교차검증하려면 폴드 쪼개줘야
너무 세세히 쪼개면
오래걸려, 교차검정 잘 안이루어질 수 있어
일반적으로 5~10정도
1. dt 만들어
2훈련시켜
3교차훈련
과정을 했는데
교차검증은 사실 해당 모델을 훈련안시키고(훈련시키는 과정에서 섞여 train_test_split)
모델 객체만 던져줘도 돼(대신, 한 번 섞어줘야 해 => 분할기 필요)
분할기 하나의 클래스로 존재
cross_validate 가 훈련까지 시켜주기 때문에 따로 훈련시켜주지 않아도 돼
대신
그리드서치객체 내부에는
객체를 누가 가지고 있고
파라미터값이 어떤 변수가 갖고 있고
결정트리 객체를 얻어내려면
cv 기본 값 5
25번 훈련 해
25개 모델 중 제일 베스트 모델 객체를 꺼내줘 best_estimator_
진짜 베스트인지 score로 확인
그리드서치, 어쩌구는
결정트리에서만 사용하는 게 아니라
파라미터를 만들 때 모델마다 매개변수 명 달라
그리드서치할 때 모델의 매개변수명 알고 있어야 해
# 데이터 불러오기
import pandas as pd
wine = pd.read_csv('https://bit.ly/wine_csv_data')
# 넘파이 배열로 변환
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)
# 결정나무
from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier(random_state=42)
#
from sklearn.model_selection import cross_validate, StratifiedKFold
scores = cross_validate(dt, train_input, train_target, cv=StratifiedKFold())
print(scores)
# 교차 검증의 최종 점수
import numpy as np
print(np.mean(scores['test_score']))
1. 어떤 모델의 하이퍼파라미터를 선택할 건지(모델 선택 필요)
2. 해당 모델의 매개변수를 지정
3. 그 매개변수에 넣어줄 값이 필요해
훈련 세트를 그리드 서치로 수행
평균 검증 점수 등 매개변수 조합
4.
# 데이터 불러와
import pandas as pd
wine = pd.read_csv('https://bit.ly/wine_csv_data')
# 넘파이 배열로 변환
data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
target = wine['class'].to_numpy()
# train 80% / test 20%
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)
##########################훈련세트와 검증세트로 나누기##############################
# train을 sub(훈련세트) / val(검증)으로 쪼개
sub_input, val_input, sub_target, val_target = train_test_split(
train_input, train_target, test_size=0.2, random_state=42)
print(sub_input.shape, val_input.shape) >>> (4157, 3) (1040, 3)
# 결정트리
from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier()
dt.fit(sub_input, sub_target)
print(dt.score(sub_input, sub_target)) >>> 0.9971133028626413
print(dt.score(val_input, val_target)) >>> 0.8596153846153847
################################ 교차검증 ################################
# 교차검증 cross_validate() 함수 기본 값 5개 #결과값 반드시 딕셔너리로 만들어져
from sklearn.model_selection import cross_validate
scores = cross_validate(dt, train_input, train_target)
print(scores) >>> {'fit_time': array([0.00907803, 0.0089016 , 0.00902104, 0.00905895, 0.00889564]),
'score_time': array([0.00107121, 0.00111842, 0.00104046, 0.00129819, 0.0010705 ]),
'test_score': array([0.86826923, 0.85192308, 0.8719923 , 0.85466795, 0.84119346])}
# 교차검증의 최종 점수 #키 값이 test_score인 값만 뽑아서 평균
import numpy as np
print(np.mean(scores['test_score'])) >>> 0.8576092026356704
################################KFold 분할기#######################################
# cross_validate() 검증세트 떼어낼 필요없이 훈련 세트 전체를 함수에 전달
# 단, 훈련 세트를 섞어줘야 해 => 분할기 필요 => KFold 분할기 사용
# cross_validate(객체명, 훈련세트 데이터)
from sklearn.model_selection import StratifiedKFold
scores = cross_validate(dt, train_input, train_target, cv=StratifiedKFold())
print(np.mean(scores['test_score'])) >>> 0.8570326497371734
# 10-폴드 교차 검증 수행
dt = DecisionTreeClassifier()
splitter = StratifiedKFold(n_splits=10, shuffle=True, random_state=42)
scores = cross_validate(dt, train_input, train_target, cv=splitter)
print(np.mean(scores['test_score']))
하이퍼파라미터 튜닝
# 그리드서치
# 최적의 하이퍼파라미터 값을 모르면 계속 실행해 봐야해
from sklearn.model_selection import GridSearchCV # 어떤 파라미터값을 다양하게 넣어주려면 반드시 딕셔너리로 묶어어야 해
params = {'min_impurity_decrease': [0.0001, 0.0002, 0.0003, 0.0004, 0.0005]}
# 딕셔너리 하나의 모델에 매개변수 여러개에
#각 매개변수에 키명을 다양하게 뿌리려면 딕셔너리
# 키명은 해당 모델이 가지고 있는 고유의 매개변수 명을 써야해(반드시 문자열로)
# 값은 매개변수한테 넣어서 평가해 봐라 # 값 리스트 필요해
# GridSearchCV
gs = GridSearchCV(DecisionTreeClassifier(random_state=42), params,n_jobs=-1)
# GPU 병렬처리를 하는데 다쓰겠다
# 훈련
gs.fit(train_input, train_target)
# 가장 훌륭한 모델 best_estimator_
dt = gs.best_estimator_ # 25개 모델 중 제일 베스트 모델 객체를 꺼내줘 best_estimator_
print(dt.score(train_input, train_target)) # 진짜 베스트인지 score로 확인
# 최적의 파라미터 값 best_params_
print(gs.best_params_)
# 5번 교차 검증 한 값을 확인
print(gs.cv_results_['mean_test_score'])
# 가장 큰값의 인데스 번호를 반환
# 눈으로 일일이 값을 확인하기 힘들때
best_index = np.argmax(gs.cv_results_['mean_test_score'])
print(gs.cv_results_['params'][best_index])
# 매개변수
params = {'min_impurity_decrease': np.arange(0.0001, 0.001, 0.0001),
'max_depth': range(5, 20, 1),
'min_samples_split': range(2, 100, 10)
}
# 6,750개 중 최적의 모델 찾아줘
gs = GridSearchCV(DecisionTreeClassifier(random_state=42), params, n_jobs=-1)
gs.fit(train_input, train_target) # best_params_ 구한 매개변수 값들을 가지고 훈련
print(gs.best_params_)
print(np.max(gs.cv_results_['mean_test_score']))
싸이파이
과학으로 만들어진 라이브러리
결정트리모델
1.
or
2. 어차피 최고의 모델이 들어가 있는 상태
해당 모델 꺼내올 수 있어
해
랜덤서치
score 평가 점수 높이기 위해서
첫째. 샘플링개수 늘려 보고
둘째 매개변수의 범위 값을 조정
랜덤이 더빨라
5-3. 트리의 앙상블
1. 랜덤포레스트
훈련할 데이터를 랜덤하게 만든다
이 때 중복허용(뽑고 다시 넣어) <= 부트스트랩 샘플(bootstrap sample)
부트스트랩 샘플의 크기는 훈련데이터 세트 크기와 동일
전체 특성의 제곱근만큼의 특성을 선택
(ex. 4개의 특성이 있다면 노드마다 2개를 랜덤하게 선택해서 조건을 만들어줘)
기본적으로 100개의 결정트리를 가지고 결과를 만들어
분류 => 각 트리의 클래스별 확률을 평균하여 가장 높은 확률의 클래스를 예측으로
회귀 => 각 트리의 예측을 평균
랜덤하게 선택한 샘플과 특성을 사용하기 때문에 과대적합 방지, 안정적인 성능
하나의 특성에 과돠하게 집중하지 않고 좀 더 많은 특성이 훈련에 참여할 기회
2. 엑스트라 트리
전체 특성 중 일부를 랜덤하게 선택하여 노드 분할하는 데 사용
랜덤포레스트와 차이점 부트스트랩 샘플 사용하지 않음
대신, 노드 분할 시 무작위 분할
단점: 성능이 낮아
장점: 과대적합 방지, 검증세트 점수를 높이는 효과 , 속도가 빨라
3. 그라디언트 부스팅
결정트리의 장점 + 경사하강법을 도입한 것
깊이가 얕은 결정 트리를 사용하여 이진 트리 오차를 보완하기 위해 새롭게 개발된 트리 앙상블
결정트리가 경사하강법처럼 움직여
기본적으로 깊이가 3인 결정트리를 100개 사용
과대적합에 강하고, 일반적으로 높은 일반화 성능을 기대할 수 있음.
깊이가 얕아 속도가 빨라
경
분류 => 로지스틱 손실함수
회귀 => 평균제곱 오차함수
결정트리를 계속 추가하면 가장 낮은 곳을 찾아
훈련 속도가 느려
4. 히스토그램 기반 그레이던트 부스팅
정형데이터를 다루는 머신러닝 알고리즘 중에 가장 인기가 높음
입력의 특성을 256개의 구간으로 분리
따라서 노드를 분할할 때 최적의 분할을 매우 빠르게 찾을 수 있다
256개의 구간 중에서 하나를 떼어 놓고 누락된 값을 위해 사용
따라서 누락 데이터를 처리할 필요가 없다
데이터베이스 생성
테이블 생성
필드(숫자 / 문자)
정형 데이터
비정형 데이터
NoSQL 내가 필요한만큼 그때그때
기존에 저장할 수 없는 데이터
몽고DB
NoSQL과 장점 합쳐
mariaDB
지금까지 배운 머신러닝 알고리즘 정형 데이터에 잘맞아
정형 데이터를 다루는 데 가장 뛰어난 성과를 내는 알고리즘 => 머신러닝/앙상블 학습
오디오, 사진 등 비정형 데이터를 주로 다루는 거 => 딥러닝 / 신경망 알고리즘
1. 랜덤 포레스트
결정트리 100개들어가
훈련데이터 샘플 섞여져 있는 데 그 중에서 랜덤하게 뽑는다
부트스트랩 샘플 중복된 샘플 뽑을 ㅜㅅ 있어
'MLOps 개발자 양성과정 > ml&dl' 카테고리의 다른 글
[Day-55] chap07.딥러닝_인공신경망 (0) | 2023.03.13 |
---|---|
[Day-54] chap.06_비지도 학습 (0) | 2023.03.12 |
[Day-52] 로지스틱 회귀 / 확률적 경사 하강법 (0) | 2023.03.08 |
[Day-51] 머신러닝_ 회귀 (0) | 2023.03.07 |
[Day-50] 머신러닝 k-Nearest Neighbors (0) | 2023.03.06 |