열렬히.뛰기

2장 연습문제

머신러닝 & 딥러닝 > 핸즈온 머신러닝 2 > 2장 연습문제

2. 머신러닝 프로젝트 처음부터 끝까지

1번 문제

  • 2.7장 그리드 서치에서 했던 걸 떠 올리기.
    • 이제 서포트 벡터 머신(SVM)이라는 모델을 추가해 보자.
  • SVM은 파라미터 중 kernel을 조정하므로써 값을 다르게 할 수 있다.
    • kernel의 종류 : linear, rbf 등등
  • 다양한 커널을 넣어보고 뭐가 제일 좋은지 보자.
python
from sklearn.model_selection import GridSearchCV

param_grid = [
        {'kernel': ['linear'], 'C': [10., 30., 100., 300., 1000., 3000., 10000., 30000.0]},
        {'kernel': ['rbf'], 'C': [1.0, 3.0, 10., 30., 100., 300., 1000.0],
         'gamma': [0.01, 0.03, 0.1, 0.3, 1.0, 3.0]},
    ]

svm_reg = SVR()
grid_search = GridSearchCV(svm_reg, param_grid, cv=5, scoring='neg_mean_squared_error', verbose=2)
grid_search.fit(housing_prepared, housing_labels)

시간이 상당히 많이 걸린다.

param_grid 속 ‘C’값, gamma값, GridSearchCV 속 cv를 조정해가며 보자.

최상 모델의 점수는 다음과 같다.

python
negative_mse = grid_search.best_score_
rmse = np.sqrt(-negative_mse)
print("RMSE:", rmse)

RMSE: 70286.61838178603 가 나온다.

하이퍼 파라미터도 확인해보자.

python
grid_search.best_params_

{'C': 30000.0, 'kernel': 'linear'} ; 즉, 선형커널이 RBF 커널보다 낫다.

2번 문제

  • 2.7장의 GridSearchCV를 RandomizedSearchCV로 바꿔보자.
python
from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import expon, reciprocal

param_distribs = {
        'kernel': ['linear', 'rbf'],
        'C': reciprocal(20, 200000),
        'gamma': expon(scale=1.0),
    }
svm_reg = SVR()
rnd_search = RandomizedSearchCV(svm_reg, param_distributions=param_distribs,
                                n_iter=30, cv=3, scoring='neg_mean_squared_error',
                                verbose=2, random_state=42)
rnd_search.fit(housing_prepared, housing_labels)

시간이 상당히 많이 걸린다. RandomizedSearchCV의 파라미터 중 n_iter, cv 값을 조정해보자.

최상 모델의 점수는 다음과 같다.

python
negative_mse = rnd_search.best_score_
rmse = np.sqrt(-negative_mse)
print("RMSE:", rmse)

RMSE: 55312.44715561121가 나온다.

하이퍼 파라미터도 확인해보자.

python
rnd_search.best_params_

{'C': 157055.10989448498, 'gamma': 0.26497040005002437, 'kernel': 'rbf'} 가 나온다.

보통 랜덤서치가 같은 시간안에 그리드서치보다 더 좋은 하이퍼파라미터를 찾는다.

3번 문제

  • 2.5장에서 변환기에 대해 배웠다.
  • 가장 중요한 특성을 선택하는 변환기를 준비 파이프라인에 추가해 보자.
python
from sklearn.base import BaseEstimator, TransformerMixin

def indices_of_top_k(arr, k):
    return np.sort(np.argpartition(np.array(arr), -k)[-k:])

class TopFeatureSelector(BaseEstimator, TransformerMixin):
    def __init__(self, feature_importances, k):
        self.feature_importances = feature_importances
        self.k = k
    def fit(self, X, y=None):
        self.feature_indices_ = indices_of_top_k(self.feature_importances, self.k)
        return self
    def transform(self, X):
        return X[:, self.feature_indices_]

선택할 특성의 갯수를 지정하고, 최상의 k개 특성 인덱스를 확인

python
k = 5

top_k_feature_indices = indices_of_top_k(feature_importances, k)
top_k_feature_indices

array([ 0, 1, 7, 9, 12], dtype=int64)

python
np.array(attributes)[top_k_feature_indices]

array(['longitude', 'latitude', 'median_income', 'pop_per_hhold', 'INLAND'], dtype='<U18')

맞는지 다시 확인!

python
sorted(zip(feature_importances, attributes), reverse=True)[:k]
python
# 결과

[(0.3790092248170967, 'median_income'),
 (0.16570630316895876, 'INLAND'),
 (0.10703132208204355, 'pop_per_hhold'),
 (0.06965425227942929, 'longitude'),
 (0.0604213840080722, 'latitude')]

새로운 파이프라인 만들기

python
preparation_and_feature_selection_pipeline = Pipeline([
    ('preparation', full_pipeline),
    ('feature_selection', TopFeatureSelector(feature_importances, k))
])

housing_prepared_top_k_features = preparation_and_feature_selection_pipeline.fit_transform(housing)

샘플의 특성 & 최상의 k개 특성 확인

python
# 처음 3개 샘플 특성
print(housing_prepared[0:3, top_k_feature_indices])

# 최상의 k개 특성 확인
print(housing_prepared[0:3, top_k_feature_indices])

결과는 다음과 같다.

python
[[-0.94135046  1.34743822 -0.8936472   0.00622264  1.        ]
 [ 1.17178212 -1.19243966  1.292168   -0.04081077  0.        ]
 [ 0.26758118 -0.1259716  -0.52543365 -0.07537122  1.        ]]


[[-0.94135046  1.34743822 -0.8936472   0.00622264  1.        ]
 [ 1.17178212 -1.19243966  1.292168   -0.04081077  0.        ]
 [ 0.26758118 -0.1259716  -0.52543365 -0.07537122  1.        ]]

4번 문제

  • 전체 데이터 준비 과정과 최종 예측을 하나의 파이프라인으로 만들어보기.
python
prepare_select_and_predict_pipeline = Pipeline([
    ('preparation', full_pipeline),
    ('feature_selection', TopFeatureSelector(feature_importances, k)),
    ('svm_reg', SVR(**rnd_search.best_params_))
])

prepare_select_and_predict_pipeline.fit(housing, housing_labels)

몇 개의 샘플에 전체 파이프라인 적용.

python
some_data = housing.iloc[:4]
some_labels = housing_labels.iloc[:4]

print("Predictions:\t", prepare_select_and_predict_pipeline.predict(some_data))
print("Labels:\t\t", list(some_labels))

결과는 다음과 같다. 잘 작동하는 것 같다.

python
Predictions:	 [ 83384.49158095 299407.90439234  92272.03345144 150173.16199041]
Labels:		 [72100.0, 279600.0, 82700.0, 112500.0]

5번 문제

  •  GridSearchCV를 사용해 준비 단계의 옵션을 자동으로 탐색.
  • 파이프라인을 만드는 문제
python
full_pipeline.named_transformers_["cat"].handle_unknown = 'ignore'

param_grid = [{
    'preparation__num__imputer__strategy': ['mean', 'median', 'most_frequent'],
    'feature_selection__k': list(range(1, len(feature_importances) + 1))
}]

grid_search_prep = GridSearchCV(prepare_select_and_predict_pipeline, param_grid, cv=3,
                                scoring='neg_mean_squared_error', verbose=2)
grid_search_prep.fit(housing, housing_labels)
  • 굉장히 처리 과정이 많으므로 GridSearchCV의 cv 값을 조정하자. 기본적으로 48 candidate이기 때문에 잘 계산해야 한다.
  • ISLAND 특성은 데이터 값이 1개라 중간중간 오류가 나오겠지만, 잘못된 것이 아니므로 계속 실행! 중간중간 다음과 같은 문구가 나오면 성공이다.

[CV] END feature_selection__k=2, preparation__num__imputer__strategy=mean; total t...

최상의 Imputer 정책을 찾아보자.

python
grid_search_prep.best_params_

{'feature_selection__k': 1, 'preparation__num__imputer__strategy': 'mean'}

most_frequent가 제일 중요하고, 거의 모든 특성이 유효하다.

단, 마지막 ISLAND 특성은 제외!