1. 데이터 불러오기
import pandas as pd
wine = pd.read_csv('https://bit.ly/wine_csv_data')
2. 데이터 확인 및 전처리
판다스 데이터프레임의 유용한 메서드 2개
info()
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)
3. 데이터 표준화
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
ss.fit(train_input)
train_scaled = ss.transform(train_input)
test_scaled = ss.transform(test_input)
4. 로지스틱 회귀 모델 훈련
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression()
lr.fit(train_scaled, train_target)
훈련된 모델의 성능을 훈련 세트와 테스트 세트에서 평가합니다.
결정 트리 모델은 데이터를 스무고개처럼 질문을 통해 분류하며, 데이터를 잘 나눌 수 있는 질문을 찾아가며 정확도를 높입니다.
사이킷런의 DecisionTreeClassifier 클래스를 사용하여 결정 트리 모델을 훈련합니다.
5. 결정 트리 모델 훈련
from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier(random_state=42)
dt.fit(train_scaled, train_target)
결정 트리 모델의 훈련 세트와 테스트 세트에서의 성능을 평가합니다.
6. 결정 트리 시각화
결정 트리를 시각화하기 위해 plot_tree() 함수를 사용합니다
import matplotlib.pyplot as plt
from sklearn.tree import plot_tree
plt.figure(figsize=(10,7))
plot_tree(dt, max_depth=1, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()
밑 결과를 통해 트리의 구조 및 각 노드에서 수행되는 분류 기준을 시각적으로 파악할 수 있습니다.
결정 트리 모델은 노드와 가지로 구성되며, 노드에서 특정 조건을 검사하고 그 결과에 따라 가지를 따라 이동합니다. 일반적으로 하나의 노드는 2개의 가지를 가지게 됨
노드(node) - 특성에 대한 테스트를 수행
가지(branch) - 테스트 결과를 나타냄
트리의 시각화
결정 트리를 시각화하려면 plot_tree() 함수를 사용할 수 있습니다. 이 함수를 통해 트리의 깊이를 제한하고, 노드의 색을 클래스에 따라 칠할 수 있습니다. 또한 feature_names 매개변수를 사용하여 특성의 이름을 표시할 수 있습니다.
plt.figure(figsize=(10, 7))
plot_tree(dt, max_depth=1, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()
결정 트리에서 노드를 나누는 기준은 불순도입니다. 불순도는 노드의 클래스 분포의 혼잡도를 나타내며, 주요한 기준으로는 지니 불순도(Gini impurity)와 엔트로피 불순도(Entropy impurity)가 있습니다.
지니 불순도(Gini impurity): 클래스 비율의 제곱을 더한 다음 1에서 뺀 값으로 계산됩니다. 결정 트리의 기본 불순도 지표입니다.
엔트로피 불순도(Entropy impurity): 클래스 비율을 밑이 2인 로그로 곱하여 계산합니다.
불순도의 차이를 계산하여 정보 이득(Information Gain)을 최대화하기 위해 데이터를 분할합니다. 정보 이득은 부모 노드와 자식 노드 간의 불순도 차이로 정의됩니다.
결정 트리는 데이터를 분할하기 위해 불순도를 기준으로 사용하며, 정보 이득을 최대화하도록 노드를 분할합니다. 이를 시각화하여 노드의 특성과 클래스 분포를 살펴볼 수 있습니다.
가지치기는 결정 트리에서 모델의 일반화 성능을 향상시키기 위한 중요한 기술입니다. 결정 트리의 가지치기는 트리의 최대 깊이를 제한하여 모델을 더 간결하게 만드는 방법 중 하나입니다. 이를 통해 훈련 세트에 과적합되는 것을 방지할 수 있습니다.
dt = DecisionTreeClassifier(max_depth=3, random_state=42)
dt.fit(train_scaled, train_target)
import matplotlib.pyplot as plt
from sklearn.tree import plot_tree
plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()
이를 통해 루트 노드부터 리프 노드까지의 경로를 시각적으로 확인할 수 있습니다.
특성 중요도
결정 트리 모델은 각 특성의 중요도를 계산해줍니다. 특성 중요도는 각 노드의 정보 이득과 전체 샘플에 대한 비율을 곱한 후 특성별로 더하여 계산합니다. 중요도는 트리 노드에서 분기하는 결정에 특성이 얼마나 기여하는지를 나타냅니다.
print(dt.feature_importances_)
특성 중요도를 통해 어떤 특성이 모델에서 가장 유용한 역할을 하는지 확인할 수 있으며, 이를 통해 특성 선택에 활용할 수 있습니다.
훈련 세트의 입력 데이터와 타깃 데이터를 train_input과 train_target배열에 저장하고
그 다음 train_input과 train_target을 다시 train_test_split() 함수에 넣어 훈련 세트 sub_input, sub_target과 검증 세트 val_input, val_target을 만듭니다.
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)
sub_input, val_input, sub_target, val_target = train_test_split(train_input, train_target, test_size=0.2, random_state=42)
dt = DecisionTreeClassifier(random_state=42)
dt.fit(sub_input, sub_target)
print(dt.score(sub_input, sub_target))
print(dt.score(val_input, val_target))
검증 세트의 성능을 평가하고 모델이 과대적합되었다면, 매개변수를 조정하여 더 나은 모델을 찾을 수 있습니다.
반복적으로 모델을 훈련하고 검증 세트를 사용하여 성능을 평가하며 매개변수를 조정합니다.
역할
종류
사이킷런의 교차 검증 함수
from sklearn.model_selection import cross_validate
from sklearn.model_selection import StratifiedKFold
from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier(random_state=42)
scores = cross_validate(dt, train_input, train_target, cv=StratifiedKFold())
print(np.mean(scores['test_score']))
교차 검증에서 훈련 세트를 섞지 않고 사용하려면 기본적으로 StratifiedKFold(분류 모델) 또는 KFold(회귀 모델)를 사용합니다.
k-폴드 교차 검증 (k-fold cross validation)
훈련 세트를 섞어서 사용하려면 분할기(splitter)를 지정해야 합니다.
from sklearn.model_selection import KFold
scores = cross_validate(dt, train_input, train_target, cv=StratifiedKFold())
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']))
모델 파라미터: 머신러닝 모델이 학습하는 파라미터
파라미터(parameter, 매개변수): 학습 과정에서 생성되는 변수
하이퍼파라미터: 머신러닝 모델이 학습할 수 없어서 사용자가 지정해야만 하는 파라미터 (사람의 개입 없이 하이퍼파라미터를 자동으로 튜닝하는 기술을 'AutoML' 이라고 합니다)
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)
gs.fit(train_input, train_target)
dt = gs.best_estimator_
best_index = np.argmax(gs.cv_results_['mean_test_score'])
print(gs.cv_results_['params'][best_index])
GridSearchCV 클래스를 사용하여 최적의 매개변수를 탐색하고, 최상의 매개변수, 모델, 및 교차 검증 점수를 얻을 수 있습니다.
가능한 모든 조합을 시도하는 대신 각 반복마다 하이퍼파라미터에 랜덤으로 대입하여 지정한 횟수만큼 평가.
먼저, SciPy 라이브러리에서 uniform과 randint 클래스를 임포트합니다. 이 두 클래스는 주어진 범위에서 값들을 균등하게 샘플링할 수 있습니다.
싸이파이(scipy)는 어떤 라이브러리인가
- 싸이파이는 파이썬의 핵심 과학 라이브러리 중 하나이다. 적분, 보간, 선형대수, 확률 등을 포함한 수치 계산 전용 라이브러리이다. 사이킷런은 넘파이와 싸이파이 기능을 많이 사용한다.
from scipy.stats import uniform, randint
uniform 클래스는 주어진 범위 내에서 실수 값을 샘플링하고, randint 클래스는 정수 값을 샘플링합니다. 예를 들어, 0에서 10 사이의 정수를 랜덤하게 샘플링해보겠습니다.
rgen = randint(0, 10)
samples = rgen.rvs(10)
여기서 rvs 메서드는 지정한 횟수만큼 샘플링하여 배열로 반환합니다. 샘플링 결과는 무작위성에 따라 다를 수 있습니다.
uniform 클래스의 사용법도 동일하며, 0에서 1 사이의 실수를 샘플링해보겠습니다.
ugen = uniform(0, 1)
samples = ugen.rvs(10)
샘플링 결과는 0과 1 사이의 임의의 실수입니다. 랜덤 서치는 이러한 확률 분포 객체를 활용하여 매개변수 값을 샘플링하고 교차 검증을 수행하여 최적의 매개변수 조합을 찾는 방식으로 동작합니다.
랜덤 서치의 사용
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
rs = RandomizedSearchCV(DecisionTreeClassifier(random_state=42), params, n_iter=100, n_jobs=-1, random_state=42)
rs.fit(train_input, train_target)
랜덤 서치는 총 100번(n_iter 매개변수) 샘플링하여 교차 검증을 수행하고 최적의 매개변수 조합을 찾습니다. 결과를 확인하기 위해 최적의 매개변수와 교차 검증 점수를 출력합니다.
best_params = rs.best_params_
best_score = np.max(rs.cv_results_['mean_test_score'])
랜덤 서치는 랜덤하게 샘플링하기 때문에 실행할 때마다 결과가 조금씩 다를 수 있습니다.
rf = RandomForestClassifier(n_jobs=-1, random_state=42)
scores = cross_validate( rf, train_input, train_target,return_train_score=True, n_jobs=-1)
객체를 생성하고 cross_validate()함수를 사용하여 교차 검증을 수행하였습니다.
훈련 세트와 검증 세트의 점수를 비교하면 과대적합을 파악하는데 용이합니다
rf = RandomForestClassifier(oob_score=True, n_jobs= -1, random_state=42)
rf.fit(train_input, train_target)
RandomForestClassifier의 oob_score 매개변수를 활용하여 OOB (out of bag) 점수를 계산하였습니다.
OOB 점수를 사용하면 교차 검증을 대신할 수 있어서 결과적으로 훈련 세트에 더 많은 샘플을 사용할 수 있습니다.
랜덤 포레스트
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
엑스트라 트리
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
랜덤 포레스트와 엑스트라 트리의 결과는 비슷하며, 데이터셋이 간단한 경우 큰 차이를 보이지 않습니다. 엑스트라 트리가 조금 더 무작위성이 크기 때문에 더 많은 결정 트리를 훈련해야 할 수 있습니다.