📗강의노트/핸즈온 머신러닝

[핸즈온 머신러닝] 제 6장 연습문제 풀이

728x90
반응형

Exercise Part. 6

Decision Tree

1. 백만 개의 샘플을 가진 훈련 세트에서 (규제 없이) 훈련시킨 결정 트리의 깊이는 대략 얼마일까요?

m개의 리프 노드를 포함한 균형이 잘 잡힌 이진 트리의 깊이는 을 반올림한 것과 같다.


이진 결정 트리를 제한을 두지 않고 훈련시키면 훈련 샘플마다 하나의 리프 노드가 되므로 어느 정도 균형이 잘 잡힌 트리가 된다. 따라서 훈련 세트에 백만 개 샘플이 있다면 결정 트리의 깊이는

이 될 것이다.

2. 한 노드의 지니 불순도가 보통 그 부모보다 작을까요, 아니면 클까요? 일반적으로 작거나 클까요, 아니면 항상 작거나 클까요?

한 노드의 지니 불순도는 일반적으로 부모의 불순도 보다 낮다. 이는 자식의 지니 불순도의 가중치 합이 최소화되는 방향으로 각 노드를 분할하는 CART 훈련 알고리즘의 비용 함수 때문이다.

항상 그런 것은 아니다. 기존에 A 클래스 4개, B 클래스 1개를 포함한 노드가 있다고 생각해보자. 이 노드의 지니 불순도는  이다.

A, B, A, A, A 순서로 나열되어있다고 생각하자.

노드를 A,B를 가진 자식노드와 A,A,A를 가진 자식 노드를 만든다. 그러면 A,B를 가지는 자식 노드의 지니 불순도는  가 되어 부모 노드보다 높아질 수 있다. (AAA는 0)

따라서 가중치를 둔 전체 지니 불순도는  로 0.2가 되어 부모의 지니 불순도 보다는 낮다.

3. 결정 트리가 훈련 세트에 과대적합되었다면 max_depth를 줄이는 것이 좋을까요?

모델에 규제를 가해야하기 때문에 max_depth를 낮추는 것이 좋다! ( 차수 줄이기 )

4. 결정 트리가 훈련 세트에 과소적합되었다면 입력 특성의 스케일을 조정하는 것이 좋을까요?

결정 트리는 훈련 데이터의 스케일이나 원점에 맞추어져 있는지 상관하지 않는다. 이것이 결정 트리의 장점 중 하나이다. 그러므로 스케일 조정은 시간낭비이다.

5. 백만 개의 샘플을 가진 훈련 세트에 결정 트리를 훈련시키는 데 한 시간이 걸렸다면, 천만 개의 샘플을 가진 훈련 세트에 결정 트리를 훈련시키는 데는 대략 얼마나 걸릴까요?

결정 트리 훈련의 계산 복잡도는  이다.

훈련 세트의 크기에 10을 곱하면 훈련 시간은  배 늘어난다.

이면, k= 11.7시간 정도이다.

6. 십만 개의 샘플을 가진 훈련 세트가 있다면 presort=True로 지정하는 것이 훈련 속도를 높일까요?

훈련 세트가 수천 개 이하의 샘플 정도로 작을 경우에만 presort=True로 지정했을 때, 데이터를 미리 정렬하여 훈련 속도를 높일 수 있다. 하지만 훈련 세트가 클 경우에는 속도가 많이 느려진다.

7. moons 데이터셋에 결정 트리를 훈련시키고 세밀하게 튜닝해보세요.

7-a . make_moon ( n_sample=1000, noise=0.4)를 사용해 데이터셋을 생성합니다

In [12]:
from sklearn.datasets import make_moons

X,y = make_moons(n_samples=1000, noise=0.4, random_state=42)

7-b. 이를 train_test_split( )을 사용해 훈련 세트와 테스트 세트로 나눈다

In [13]:
from sklearn.model_selection import train_test_split

X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=42)

7-c. DecisionTreeClassifier의 최적의 매개변수를 찾기 위해 교차 검증과 함께 그리드 탐색을 수행한다.(GridSearchCV) 힌트 : 여러가지 max_leaf_nodes 값을 시도해보세요!

In [14]:
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV

tree_clf = DecisionTreeClassifier(random_state=42)

params = {'max_leaf_nodes' : list(range(2,100)),'min_samples_split' : [2,3,4]}

grid_search_cv = GridSearchCV(tree_clf,param_grid=params,cv=3,n_jobs=-1,verbose=1)

grid_search_cv.fit(X_train,y_train)
Fitting 3 folds for each of 294 candidates, totalling 882 fits
[Parallel(n_jobs=-1)]: Using backend LokyBackend with 4 concurrent workers.
[Parallel(n_jobs=-1)]: Done 295 tasks      | elapsed:    3.4s
[Parallel(n_jobs=-1)]: Done 882 out of 882 | elapsed:    3.7s finished
Out[14]:
GridSearchCV(cv=3, error_score='raise-deprecating',
       estimator=DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=None,
            max_features=None, max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=2,
            min_weight_fraction_leaf=0.0, presort=False, random_state=42,
            splitter='best'),
       fit_params=None, iid='warn', n_jobs=-1,
       param_grid={'max_leaf_nodes': [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99], 'min_samples_split': [2, 3, 4]},
       pre_dispatch='2*n_jobs', refit=True, return_train_score='warn',
       scoring=None, verbose=1)
In [15]:
grid_search_cv.best_estimator_
Out[15]:
DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=None,
            max_features=None, max_leaf_nodes=4, min_impurity_decrease=0.0,
            min_impurity_split=None, min_samples_leaf=1,
            min_samples_split=2, min_weight_fraction_leaf=0.0,
            presort=False, random_state=42, splitter='best')

7-d. 찾은 매개변수를 사용해 전체 훈련 세트에 대해 모델을 훈련시키고 테스트 세트에서 성능을 측정합니다. 대략 85~87%

In [16]:
from sklearn.metrics import accuracy_score

# 별도의 훈련이 필요없다. GridSearchCV는 최적의 모델로 다시 훈련시키기 때문이다.

y_pred = grid_search_cv.best_estimator_.predict(X_test)
accuracy_score(y_test,y_pred)
Out[16]:
0.855

8. 랜덤 포레스트를 만들어보세요.

8-a. 이전 연습문제에 이어서, 훈련 세트의 서브셋을 1,000개 생성한다. 각각은 무작위로 선택된 100개의 샘플을 담고있다. 힌트: sklearn의 ShuffleSplit

In [26]:
from sklearn.model_selection import ShuffleSplit

n_trees = 1000
n_instances = 100
# 100개의 array
mini_sets = []

rs = ShuffleSplit(n_splits=n_trees, test_size=len(X_train) - n_instances, random_state=42)

for train_index, test_index in rs.split(X_train):
    X_mini_train = X_train[train_index]
    y_mini_train = y_train[train_index]
    mini_sets.append((X_mini_train,y_mini_train))

8-b. 앞에서 찾은 최적의 매개변수를 사용해 각 서브셋에 결정 트리를 훈련시킨다. 테스트 세트로 이 1,000개의 결정 트리를 평가한다. 더 작은 데이터셋에서 훈련되었기 때문에 성능이 이전보다 낮다.

In [27]:
from sklearn.base import clone

# clone : Constructs a new estimator with the same parameters.
# 동일한 파라미터를 가지고 새로운 추정치를 만들어낸다. 

forest = [clone(grid_search_cv.best_estimator_) for _ in range(n_trees)]

acc_scores = []

for tree, (X_mini_train,y_mini_train) in zip(forest,mini_sets):
    tree.fit(X_mini_train,y_mini_train)
    
    y_pred = tree.predict(X_test)
    acc_scores.append(accuracy_score(y_test,y_pred))
    
np.mean(acc_scores)
Out[27]:
0.817115

8-c. 마술을 부릴 차례! 각 테스트 샘플에 대해 1,000개의 결정 트리 예측을 만들고 다수로 나온 예측만 취한다. 그러면 테스트 세트에 대한 "다수결 예측"이 만들어진다. ( scipy 의 mode( ) )

In [28]:
Y_pred = np.empty([n_trees, len(X_test)], dtype=np.uint8)

for tree_idx, tree in enumerate(forest):
    Y_pred[tree_idx] = tree.predict(X_test)
In [29]:
from scipy.stats import mode

y_pred_major_vote,n_votes = mode(Y_pred,axis=0)

8-d. 테스트 세트에서 이 예측을 평가한다. 앞선 모델보다 조금 높은 정확도를 얻을 수 있다. "랜덤 포레스트 분류기"를 훈련했다.

In [30]:
accuracy_score(y_test,y_pred_major_vote.reshape([-1]))
Out[30]:
0.85


728x90
반응형