step 1. 데이터 가공하기
import pandas as pd
wine = pd.read_csv("https://bit.ly/wine_csv_data")
wine.head()
alcohol | sugar | pH | class | |
---|---|---|---|---|
0 | 9.4 | 1.9 | 3.51 | 0.0 |
1 | 9.8 | 2.6 | 3.20 | 0.0 |
2 | 9.8 | 2.3 | 3.26 | 0.0 |
3 | 9.8 | 1.9 | 3.16 | 0.0 |
4 | 9.4 | 1.9 | 3.51 | 0.0 |
# describe() 메소드
wine.describe()
alcohol | sugar | pH | class | |
---|---|---|---|---|
count | 6497.000000 | 6497.000000 | 6497.000000 | 6497.000000 |
mean | 10.491801 | 5.443235 | 3.218501 | 0.753886 |
std | 1.192712 | 4.757804 | 0.160787 | 0.430779 |
min | 8.000000 | 0.600000 | 2.720000 | 0.000000 |
25% | 9.500000 | 1.800000 | 3.110000 | 1.000000 |
50% | 10.300000 | 3.000000 | 3.210000 | 1.000000 |
75% | 11.300000 | 8.100000 | 3.320000 | 1.000000 |
max | 14.900000 | 65.800000 | 4.010000 | 1.000000 |
wine.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6497 entries, 0 to 6496
Data columns (total 4 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 alcohol 6497 non-null float64
1 sugar 6497 non-null float64
2 pH 6497 non-null float64
3 class 6497 non-null float64
dtypes: float64(4)
memory usage: 203.2 KB
# 데이터 가공하기
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)
step 2. 로지스틱 회귀로 학습시키기
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
# 로지스틱 회귀 모델
print(lr.coef_, lr.intercept_)
[[ 0.51270274 1.6733911 -0.68767781]] [1.81777902]
5-1. Decision Tree¶
설명하기 쉬운 모델
step 1. Decision Tree 학습시키기
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
step 2. Decision Tree 시각화하기
import matplotlib.pyplot as plt
from sklearn.tree import plot_tree
plt.figure(figsize=(10, 7))
plot_tree(dt)
plt.show()
plt.figure(figsize=(10, 7))
plot_tree(dt, max_depth=1, filled=True, feature_names=["alcohol", "sugar", "pH"])
plt.show()
step 3. 지니 불순도 Gini Impurity
DecisionTreeClassifier는 gini impurity를 매개변수로 활용한다
Decision Tree는 부모 노드와 자식 노드의 불순도 차이가 가능한 크도록 트리를 만든다
gini impurity는 1 - (음성 클래스 비율^2 + 양성 클래스 비율^2)
부모 노드와 자식 노드의 불순도 차이를 정보 이득 information gain이라고 한다.
부모와 자식의 불순도 차이 = 부모 - |왼|/|부|*왼쪽 - |오|/|부|*오른쪽
step 4. 가지치기 (max_depth)
# max depth를 이용하는 방식
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
plt.figure(figsize=(20, 15))
plot_tree(dt, filled=True, feature_names=["alcohol", "sugar", "pH"])
plt.show()
# decision tree는 전처리 과정이 필요없다
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))
plt.figure(figsize=(20, 15))
plot_tree(dt, filled=True, feature_names=["alcohol", "sugar", "pH"])
plt.show()
0.8454877814123533
0.8415384615384616
# feature별 중요도
# alcohol, sugar, pH
print(dt.feature_importances_)
[0.12345626 0.86862934 0.0079144 ]
# 이득이 있는 곳에만 내려가기
# 좌우대칭이 아니게 됨
# 성능 올라감
dt = DecisionTreeClassifier(min_impurity_decrease=0.0005, random_state=42)
dt.fit(train_input, train_target)
print(dt.score(train_input, train_target))
print(dt.score(test_input, test_target))
plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=["alcohol", "sugar", "pH"])
plt.show()
0.8874350586877044
0.8615384615384616
5-2. 교차 검증과 그리드 서치¶
일반화 성능을 올바르게 테스트하기 위해서는 test set을 최대한 사용하지 말아야 한다
이를 위해서 validation set을 활용한다
모델을 고르는 과정에서 validation set으로 선택
최종적으로 평가할 때 test set 사용
# 데이터 준비하기
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
sub_input, test_input, sub_target, test_target = train_test_split(
data, target, test_size=0.2, random_state=42
)
train_input, val_input, train_target, val_target = train_test_split(
sub_input, sub_target, test_size=0.2, random_state=42
)
print(train_input.shape, val_input.shape, test_input.shape)
(4157, 3) (1040, 3) (1300, 3)
모델 만들고 평가하기
# train set으로 학습시킨 후 validation set으로 검증
# 그 결과, 오버피팅 되어있음을 알게 됨
from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier(random_state=42)
dt.fit(train_input, train_target)
print(dt.score(train_input, train_target))
print(dt.score(val_input, val_target))
0.9971133028626413
0.864423076923077
교차 검증 cross validation¶
훈련 셋, 검증 셋을 떼어내어 평가하는 과정을 여러 번 반복하여 모델을 개선하는 방식
보통 5-폴드 교차검증, 10-폴드 교차검증이 많이 사용됨
# sklearn의 cross_validate() 함수 이용
from sklearn.model_selection import cross_validate
scores = cross_validate(dt, sub_input, sub_target)
print(scores)
{'fit_time': array([0.01601219, 0.00800323, 0.01599908, 0.0079987 , 0.00800371]), 'score_time': array([0., 0., 0., 0., 0.]), 'test_score': array([0.86923077, 0.84615385, 0.87680462, 0.84889317, 0.83541867])}
# 교차 검증의 최종 점수
# test_score의 평균값
import numpy as np
print(np.mean(scores["test_score"]))
0.855300214703487
# 교차 검증에서 훈련 세트를 섞고 싶은 경우
# cross_validate()에서 매개변수로 cv=StratifiedKFold()를 지정해준다
# 단, 분류의 경우
from sklearn.model_selection import StratifiedKFold
scores = cross_validate(dt, sub_input, sub_target, cv=StratifiedKFold())
print(np.mean(scores["test_score"]))
# 10-fold cross validation을 하고 싶은 경우
splitter = StratifiedKFold(n_splits=10, shuffle=True, random_state=42)
scores = cross_validate(dt, sub_input, sub_target, cv=splitter)
print(np.mean(scores["test_score"]))
0.855300214703487
0.8574181117533719
from sklearn.model_selection import GridSearchCV
params = {
"min_impurity_decrease":[0.0001, 0.0002, 0.0003, 0.0004, 0.0005]
}
gs = GridSearchCV(DecisionTreeClassifier(random_state=42), params, n_jobs=-1)
# param으로 할당된 min_impurity_decrease 값마다 5-fold cross validation 수행
# n_jobs = CPU 코어 수 지정
gs.fit(sub_input, sub_target)
dt = gs.best_estimator_
print(dt.score(sub_input, sub_target))
print(gs.best_params_)
print(gs.cv_results_["mean_test_score"])
best_index = np.argmax(gs.cv_results_["mean_test_score"])
print(gs.cv_results_["params"][best_index])
0.9615162593804117
{'min_impurity_decrease': 0.0001}
[0.86819297 0.86453617 0.86492226 0.86780891 0.86761605]
{'min_impurity_decrease': 0.0001}
# max_depth와 min_samples_split, min_impurity_decrease 모두 체크하기
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)
}
gs = GridSearchCV(DecisionTreeClassifier(random_state=42), params, n_jobs=-1)
gs.fit(sub_input, sub_target)
print(gs.best_params_)
{'max_depth': 14, 'min_impurity_decrease': 0.0004, 'min_samples_split': 12}
print(np.max(gs.cv_results_["mean_test_score"]))
0.8683865773302731
랜덤 서치
값의 목록이 아니라 샘플링할 수 있는 확률 분포를 전달한다
from scipy.stats import uniform, randint
# uniform: 실수 균등 샘플링
# randint: 정수 균등 샘플링
rgen = randint(0, 10)
rgen.rvs(10)
ugen = uniform(0, 1)
ugen.rvs(10)
array([0.95318284, 0.65926649, 0.82211576, 0.54635333, 0.34811602,
0.39502395, 0.62915606, 0.557889 , 0.11120146, 0.07797304])
params = {
"min_impurity_decrease": uniform(0.0001, 0.001),
"max_depth": randint(20, 50),
"min_samples_split": randint(2, 25),
"min_samples_leaf": randint(1, 25),
}
from sklearn.model_selection import RandomizedSearchCV
gs = RandomizedSearchCV(
DecisionTreeClassifier(random_state=42),
params,
n_iter=100, # 백번 샘플링
n_jobs=-1,
random_state=42
)
gs.fit(sub_input, sub_target)
print(gs.best_params_) # 선정된 최적의 하이퍼파라미터
{'max_depth': 43, 'min_impurity_decrease': 0.00011407982271508446, 'min_samples_leaf': 19, 'min_samples_split': 18}
# 교차 검증 점수
print(np.max(gs.cv_results_["mean_test_score"]))
dt = gs.best_estimator_
print(dt.score(test_input, test_target))
0.8695428296438884
0.86
5-3. 트리의 앙상블¶
- 정형 데이터 structured data
- csv, database, excel
- 비정형 데이터 unstructured data
- 텍스트, 사진, 음악 등
- NoSQL
- 정형 데이터에서 가장 뛰어난 알고리즘이 "ensemble learning"
- 비정형 데이터는 신경망 알고리즘을 사용
랜덤 포레스트 Random Forest¶
ensemble learning의 대표 주자
결정 트리를 랜덤하게 만들어 결정 트리의 숲을 만든다
각 결정 트리의 예측을 사용해서 최종 예측을 만든다
각 트리는 부트스트랩 샘플 bootstrap sample으로 학습시킨다
부트스트랩 샘플: n개의 샘플에서 중복을 허용하며 n개를 추출한다
- 랜덤 포레스트는 100개의 결정 트리를 훈련시킨다
- 각 트리는 트리에 사용하는 속성을 제한하여 트리의 다양성을 높인다
- (분류) 예측할 때는 각 트리의 클래스별 확률을 평균내어 가장 높은 확률을 가진 클래스를 내놓는다
- (회귀) 회귀는 각 트리의 예측값을 평균낸다
# 데이터 불러오기
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
# 랜덤 포레스트로 학습시키기
rf.fit(train_input, train_target)
print(rf.feature_importances_)
[0.23167441 0.50039841 0.26792718]
# 중복 추출에서 선택되지 않은 "OOB, out of bag" 샘플로 모델 자체 테스트 가능함
rf = RandomForestClassifier(oob_score=True, n_jobs=-1, random_state=42)
rf.fit(train_input, train_target)
print(rf.oob_score_)
0.8934000384837406
엑스트라 트리 Extra Trees
랜덤 포레스트와 거의 동일한데, 부트스트랩 샘플(중복 추출 허용한 샘플)을 사용하지 않는다
엑스트라 트리에서는 특성을 무작위로 분할한다 -> 속도가 빠르나 더 많은 결정 트리를 훈련시켜야 한다
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
그레이디언트 부스팅 gradient boosting
- 깊이가 얕은 결정 트리로 이전 트리의 오차를 보완한다
- 경사 하강법 gradient descent으로 트리를 앙상블에 추가한다
- 결정 트리를 추가하면서 가장 낮은 곳(손실 함수의 낮은 곳)을 찾아 이동한다
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
히스토그램 기반 그레이디언트 부스팅 histogram-based gradient boosting
- 정형 데이터를 다루는 머신러닝 알고리즘 중 가장 인기가 높음
- feature를 256개 구간으로 나눈다 -> 최적의 분할을 빨리 찾음
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)
print(np.mean(scores["train_score"]), np.mean(scores["test_score"]))
c:\Users\.venv\lib\site-packages\sklearn\experimental\enable_hist_gradient_boosting.py:16: UserWarning: Since version 1.0, it is not needed to import enable_hist_gradient_boosting anymore. HistGradientBoostingClassifier and HistGradientBoostingRegressor are now stable and can be normally imported from sklearn.ensemble.
warnings.warn(
0.9321723946453317 0.8801241948619236
'Data Science > AI' 카테고리의 다른 글
인공지능 #6-1 | 비지도학습 - 클러스터링, 히스토그림 (0) | 2023.03.07 |
---|---|
[에러 해결] ValueError: Cannot load file containing pickled data when allow_pickle=False 해결하기 (0) | 2023.03.07 |
인공지능 #4 | 로지스틱 회귀, 시그모이드 함수, 확률적 경사 하강법 Stochastic Gradient Descent (0) | 2023.03.06 |
인공지능 #3 | K-nearest neighbor 알고리즘, 선형 회귀, 릿지 회귀, 라쏘 회귀 (0) | 2023.03.06 |
인공지능 #2 | 훈련 셋과 테스트 셋, 데이터 전처리 (0) | 2023.03.06 |