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

주요 내용

참고: 핵심 설명과 코드는 🔑로 표시되었으며 굳이 알아둘 필요가 없는 코드는 ✋로 표시되었다.

기본 설정

1부

2.3 데이터 가져오기 (p. 75)

2.3.2 데이터 다운로드 (p. 79)

2.3.3 데이터 구조 훑어보기 (p. 81)

2.3.4 테스트 세트 만들기 (p. 85)

무작위 샘플링 (p. 85)

계층별 샘플링 (p. 88)

2.4 데이터 이해를 위한 탐색과 시각화 (p. 91)

훈련세트 원본을 그대로 두고 복사해서 사용한다.

2.4.1 지리적 데이터 시각화 (p. 91)

2.4.2 상관관계 조사 (p. 94)

Pearson correlation coefficient

<그림 출처: 위키백과>

2.4.3 특성 조합으로 실험 (p. 97)

구역별 방의 총 개수와 침실의 총 개수 대신 아래 특성이 보다 유용하다.

가구당 방 개수의 역할은 여전히 미미하다.

2부

2.5 머신러닝 알고리즘을 위한 데이터 준비 (p. 99)

훈련세트를 대상으로 중간 주택 가격을 타깃값(레이블)로 사용하기 위해 다른 특성으로 분리한다.

2.5.1 데이터 정제 (p. 99)

수치형 특성 전처리 과정 1: total_bedrooms 특성에 존재하는 누락치 처리법 결정

여기서는 옵션 3을 활용한다. 즉, 누락치를 특성 중앙값으로 채운다.

SimpleImputer 변환기

SimpleImputer 변환기를 활용하면 옵션 3을 쉽게 처리할 수 있다.

중앙값이 수치형 특성에서만 계산될 수 있기 때문에 범주형 특성을 제거한 후에 SimpleImputer 변환기를 적용해야 한다.

SimpleImputer 변환기의 fit() 메서드는 지정된 통계 특성값을 계산하여 저장해 둔다.

각 특성의 중앙값이 수동으로 계산한 것과 동일하다.

transform() 메서드를 실행하여 수치형 특성을 변환한다.

앞서 누락치를 수동으로 채운 결과와 동일함을 확인할 수 있다.

누락치를 채우는데 사용한 전략이 중앙값(median)임을 다시 확인할 수 있다.

2.5.2 텍스트와 범주형 특성 다루기 (p.102)

범주형 입력 특성인 ocean_proximity 전처리 하기: 원-핫 인코딩 활용

해안 근접도(ocean_proximity) 다시 확인

범주형 특성값을 단순하게 수치화하면 다음과 같다.

수치화된 번호는 범주들의 인덱스에 해당한다. 하지만 숫자의 크기가 모델 훈련 과정에 잘못된 영향을 줄 수 있음에 주의해야 한다.

따라서 여기서는 대신에 원-핫-인코딩을 활용한다.

OneHotEncoder 변환기

OneHotEncoder 변환기의 sparse=False 하이퍼파라미터로 지정하면 밀집 행렬이 생성된다.

사용된 범주 어레이는 categories_ 속성에 저장된다.

2.5.3 나만의 변환기 (p.105)

수치형 특성 전처리 과정 2: 특성 추가

직접 변환기를 구현해야 한다.

특성 추가에 사용되는 기본의 특성들의 인덱스를 (3, 4, 5, 6) 처럼 수동으로 지정하는 것 대신에 아래와 같이 동적으로 처리하는 게 보다 좋다.

housing_extra_attribs는 넘파이 어레이이며, 따라서 기존에 사용된 columnsindex를 이용하여 DataFrame으로 복원해야 한다.

2.5.4 특성의 축척 조정 (p. 107)

수치형 특성 전처리 과정 3: 특성의 축척 조정

여기서는 사이킷런의 StandardScaler 변환기를 이용하여 표준화 축척 조정(스케일링, scaling)을 사용한다.

2.5.5 변환 파이프라인 (p.108)

수치형 특성 전처리 세 단계를 하나의 파이프라인으로 묶기

수치형 특성 파이프라인과 범주형 특성을 하나의 파이프라인으로 묶기

모든 전처리 결과는 다음과 같다.

3부

2.6 모델 선택과 훈련 (p. 110)

사이킷런이 제공하는 다양한 회귀 모델을 선택하여 훈련과 예측을 실행하는 방법 소개한다. 소개되는 모델은 다음과 같다.

또한 훈련되는 모델의 성능을 평가하는 교차 검증 방식도 소개한다. 모델 평가 기준은 RMSE(평균 제곱근 오차)를 기본으로 사용한다.

2.6.1 훈련 세트에서 훈련하고 평가하기 (p. 110)

선형 회귀 모델(LinearRegression) 훈련

실제 중간 주택 가격은 다음과 같다.

훈련 세트 대상 성능 평가

RMSE가 MAE 보다 크다. 따라서 훈련 세트에 이상치가 많이 포함되어 있다고 유추할 수 있다. 앞서 살펴 보았듯이, 여러 이상치를 제거하고 훈련시키면 좀 더 좋은 성능이 나올 수 있다. (아래 프로젝트 안내 참조)

결정 트리 회귀 모델(DecisionTreeRegressor) 훈련

훈련 및 예측 과정은 동일하다.

RMSE가 0으로 측정된다.

2.6.2 교차 검증을 사용한 평가 (p. 112)

cross_val_score 함수를 활용하여 특정 모델의 성능을 교차 검증(cross validation) 기법으로 평가한다. 사용되는 하이퍼파라미터는 다음과 같다.

결정 트리에 대한 교차 검증 결과가 좋지 않다. 즉, 앞선 결과가 완벽한 과대적합이었음이 다시 한 번 확인된다.

선형 회귀에 대한 교차 검증 결과가 오히려 좀 더 좋다.

팬다스의 시리즈(Series) 자료형이 제공하는 describe() 메서드를 이용하여 10개 검증 결과의 통계 정보를 확인할 수 있다.

랜덤 포레스트 회귀 모델(RandomForestRegressor 훈련

무작위로 선택한 특성을 이용하는 결정 트리 여러 개를 훈련 시킨 후 훈련된 모델들의 평균 예측값을 예측값으로 사용하는 모델이며, 아래 코드에서 사용된 하이퍼파라미터는 다음과 같다.

랜덤 포레스트를 대상으로 교차 검증 진행하면, 선형회귀, 결정 트리 모델보다 성능이 좋게 나온다. 하지만 교차 검증 결과가 바로 위 훈련 결과보자 좋지 않다. 즉, 위 훈련 모델이 과대적합이었다는 것을 반증한다.

2.7 모델 세부 튜팅 (p. 115)

가능성 있는 모델을 몇 개 선정한 다음에는 모델에 사용된 하이퍼파라미터의 최적값을 찾아야 한다. 좋은 파라미터를 탐색하는 세 가지 기법은 다음과 같다.

여기서는 그리드 탐색과 랜덤 탐색을 간단하게 소개하며, 앙상블 학습은 7장에서 자세히 다룬다.

2.7.1 그리드 탐색 (p.115)

GridSearchCV 객체를 활용하며, 특정 하이퍼파라미터에 대한 후보로 지정된 값들의 모든 조합에 대해 교차 검증 평가를 진행한다.

아래 코드는 랜덤 포레스트 회귀 모델의 하이퍼파라미터를 탐색한다.

최상의 하이퍼파라미터 조합은 best_params_ 속성에 저장된다.

최상의 랜덤 포레스트 회귀 모델은 best_estimator_ 속성에 저장된다.

그리드 탐색에서 테스트한 18개의 하이퍼파라미터 조합에 대한 평가 점수는 다음과 같다.

cv_results_ 속성에 그리드 탐색 과정에서 알아낸 많은 값들이 저장되어 있다. (넘파이 사전 객체로 저장됨.) 팬다스 데이터프레임으로 형변환하면 사전의 키(key)가 열(column)의 항목으로 사용된다.

✋ 그리드 탐색과 파이프라인

데이터 전처리와 그리드 탐색을 연결한 파이프라인을 이용하면 전처리 단계에서 설정해야 하는 값들을 일종의 하이퍼파라미터로 다룰 수 있다. 예를 들어,

등에 대해 어떻게 설정하는 것이 좋은지를 하이퍼파라미터로 지정해 놓으면 그리드 탐색 등을 이용하여 어떤 옵션이 좋은지 함께 탐색해준다.

조금은 고급 기술이지만, 지금까지 배운 내용을 이해한다면 어렵지 않게 적용할 수 있는 기술이다. 파이프라인과 그리드 탐색을 연동한 예제들을 아래 사이트에서 살펴볼 수 있다.

2.7.2 랜덤 탐색 (p. 118)

조합 대상인 하이퍼파라이미터 값을 지정된 구간에서 임의의 선택하는 방식을 활용한다. 탐색 공간이 커질 때 사용하며, 기타 작동 방식은 그리드 탐색과 동일하다. 아래 코드는 다음 두 하이퍼파라미터의 탐색 구간을 지정한다.

2.7.4 최상의 모델과 오차 분석 (p.118)

최상의 랜덤 포레스트 모델에서 사용된 특성들의 중요도를 확인하여 일부 특성을 제외할 수 있다.

중요도 기준으로 정렬하여 특성과 함께 보여주면 다음과 같다.

2.7.5 테스트 세트로 시스템 평가하기 (p. 119)

튜닝된 모델을 테스트 세트 데이터를 이용하여 성능을 최종적으로 평가한다. 아래 코드에서는 그리드 탐색으로 찾은 최적 모델을 활용한다. 최종 성능 편가는 지금까지 전혀 사용하지 않았던 테스트 세트를 훈련 세트와 동일하게 전처리 한 후에 성능 평가를 진행해야 한다.

테스트 세트를 대상으로 한 최종 성능(RMSE)은 아래와 같다.

얻어진 테스트 RMSE에 대한 95% 신뢰 구간을 계산하여 확률적으로 시스템의 성능을 예측할 수 있다.

z-분포를 이용한 신뢰구간은 다음과 같다.

부록: 추가 내용

전처리와 예측을 포함한 전체 파이프라인

joblib를 사용한 모델 저장

RandomizedSearchCV를 위한 Scipy 분포 함수

랜덤 탐색을 하려면 특정 옵션 변수갈들을 무작위로 선택해주는 확률분포함수를 지정해야 한다. 앞서 랜덤 탐색을 이용하여 캘리포니아 인구조사 데이터셋 분석을 위한 최상의 랜덤 포레스트 모델을 찾았을 때 사용한 옵션 변수와 확률분포는 다음과 같다.

기타 확률분포는 Scipy 패키지의 stats 모듈에 정의되어 있다. 아래는 그 중에서 기하분포 geom, 지수분포 expon, 균등분포 uniform, 정규분포 norm 등을 이용하여 무작위로 생성된 샘플들의 분포를 히스토그램으로 보여준다.

주의: 히스토그램의 y축은 도수를 가리킨다. 이것을 10,000으로 나눈 값으로 대체하면 히스토그램에서 해당 확률분포의 그래프가 그려지게 된다. 즉, 확률밀도함수의 그래프로 감싸인 영역이 표시된다. 자세한 사항은 더이상 다루지 않는다. 보다 자세한 사항은 사이파이를 이용한 확률분포 분석를 참조할 수 있다.

프로젝트

프로젝트 과제

아래의 세 가지 변환을 전처리 과정에 추가하면 훈련된 모델의 성능이 어떻게 얼마나 달라지는지 이전 모델과 비교하라.

변환 1

중간 소득과 중간 주택 가격 사이의 상관관계 그래프에서 확인할 수 있는 수평선에 위치한 데이터를 삭제한다.

변환 2

회귀 모델 훈련에 사용되는 12개의 특성 중에 세 개는 기존 9개의 특성을 조합하여 생성하였다. 12개의 특성 중에 중간 주택 가격과의 상관계수의 절댓값이 0.2 보다 작은 특성을 삭제한다.

주의사항: 특성 삭제는 훈련 세트 뿐만 아니라 테스트 세트에 대해서도 진행해야 한다. 특성이 다르면 동일한 모델을 적용할 수 없다.

변환 3

범주형 특성을 제외한 9개 특성별 히스토그램을 보면 일부 특성의 히스토그램이 좌우 비대칭이다. (전문 용어로 왜도(skewness)가 0이 아닐 때 이런 분포가 발생한다.) 대표적으로 방의 총 개수(total_rooms), 침실 총 개수(total_bedrooms), 인구(population), 가구수(households), 중간소득(median_income) 등 다섯 개의 특성이 그렇다. 앞서 언급된 5개 특성 또는 일부에 대해 로그 변환을 적용한다.

프로젝트 진행 요령 및 힌트

  1. 언급된 세 가지 변환을 우선 하나씩 구현하고 구현 가능한 변환만 접목할 것.
  2. California Housing Price Prediction 프로젝트 관련 사이트를 살펴보고 비슷하게 진행할 것.
  3. 지정된 특성값을 갖는 데이터 샘플 삭제 요령 참고 문서
  4. 상관관계 도표에서 수평선 위치 찾기
    • 방식 1: 중간 주택 가격의 히스토 그램에서 50만을 제외한 45만, 35만, 28만 근처에서의 수평선의 정확한 위치를 알아내기 위해 히스토그램을 언급된 값 근처의 구간으로 제한해서 히스토그램을 그리면 확인할 수 있을 것임. 다른 보다 편한 방식은 잘 모르겠음. 히스토그램을 제한하는 방식은 앞서 언급한 참고1, 2에서 소개한 방식 활용 가능
    • valut_count() 메서드 활용
  5. 로그 변환: 넘파이의 log() 함수를 데이터프레임에 적용. 데이터프레임의 apply() 메서드 활용.

참고: 로그 변환

로그 변환(log transformation)은 수치 데이터에 로그(log) 함수를 적용하는 변환이며, 로그 변환이 이루어진 데이터의 분포는 보다 정규 분포에 가까워진다. 아래 그림은 왜도가 0이 아닌 분포(상단)에 로그 변환을 가했을 때 생성된 분포(하단)의 왜도가 훨씬 약화되어 정규분포에 가까워지는 것을 보여준다.

<그림 출처: StackExchange>

연습문제 해답

1.

질문: 서포트 벡터 머신 회귀(sklearn.svm.SVR)를 kernel=“linear”(하이퍼파라미터 C를 바꿔가며)나 kernel=“rbf”(하이퍼파라미터 Cgamma를 바꿔가며) 등의 다양한 하이퍼파라미터 설정으로 시도해보세요. 지금은 이 하이퍼파라미터가 무엇을 의미하는지 너무 신경 쓰지 마세요. 최상의 SVR 모델은 무엇인가요?

경고: 사용하는 하드웨어에 따라 다음 셀을 실행하는데 30분 또는 그 이상 걸릴 수 있습니다.

최상 모델의 (5-폴드 교차 검증으로 평가한) 점수는 다음과 같습니다:

RandomForestRegressor보다 훨씬 좋지 않네요. 최상의 하이퍼파라미터를 확인해 보겠습니다:

선형 커널이 RBF 커널보다 성능이 나은 것 같습니다. C는 테스트한 것 중에 최대값이 선택되었습니다. 따라서 (작은 값들은 지우고) 더 큰 값의 C로 그리드서치를 다시 실행해 보아야 합니다. 아마도 더 큰 값의 C에서 성능이 높아질 것입니다.

2.

질문: GridSearchCVRandomizedSearchCV로 바꿔보세요.

경고: 사용하는 하드웨어에 따라 다음 셀을 실행하는데 45분 또는 그 이상 걸릴 수 있습니다.

최상 모델의 (5-폴드 교차 검증으로 평가한) 점수는 다음과 같습니다:

이제 RandomForestRegressor의 성능에 훨씬 가까워졌습니다(하지만 아직 차이가 납니다). 최상의 하이퍼파라미터를 확인해 보겠습니다:

이번에는 RBF 커널에 대해 최적의 하이퍼파라미터 조합을 찾았습니다. 보통 랜덤서치가 같은 시간안에 그리드서치보다 더 좋은 하이퍼파라미터를 찾습니다.

여기서 사용된 scale=1.0인 지수 분포를 살펴보겠습니다. 일부 샘플은 1.0보다 아주 크거나 작습니다. 하지만 로그 분포를 보면 대부분의 값이 exp(-2)와 exp(+2), 즉 0.1과 7.4 사이에 집중되어 있음을 알 수 있습니다.

C에 사용된 분포는 매우 다릅니다. 주어진 범위안에서 균등 분포로 샘플링됩니다. 그래서 오른쪽 로그 분포가 거의 일정하게 나타납니다. 이런 분포는 원하는 축척(scale)이 정확이 무엇인지 모를 때 사용하면 좋습니다:

reciprocal() 함수는 하이퍼파라미터의 축척에 대해 전혀 감을 잡을 수 없을 때 사용합니다(오른쪽 그래프에서 볼 수 있듯이 주어진 범위안에서 모든 값이 균등합니다). 반면 지수 분포는 하이퍼파라미터의 축척을 (어느정도) 알고 있을 때 사용하는 것이 좋습니다.

3.

질문: 가장 중요한 특성을 선택하는 변환기를 준비 파이프라인에 추가해보세요.

노트: 이 특성 선택 클래스는 이미 어떤 식으로든 특성 중요도를 계산했다고 가정합니다(가령 RandomForestRegressor을 사용하여). TopFeatureSelectorfit() 메서드에서 직접 계산할 수도 있지만 (캐싱을 사용하지 않을 경우) 그리드서치나 랜덤서치의 모든 하이퍼파라미터 조합에 대해 계산이 일어나기 때문에 매우 느려집니다.

선택할 특성의 개수를 지정합니다:

최상의 k개 특성의 인덱스를 확인해 보겠습니다:

최상의 k개 특성이 맞는지 다시 확인합니다:

좋습니다. 이제 이전에 정의한 준비 파이프라인과 특성 선택기를 추가한 새로운 파이프라인을 만듭니다:

처음 3개 샘플의 특성을 확인해 보겠습니다:

최상의 k개 특성이 맞는지 다시 확인합니다:

성공입니다! :)

4.

질문: 전체 데이터 준비 과정과 최종 예측을 하나의 파이프라인으로 만들어보세요.

몇 개의 샘플에 전체 파이프라인을 적용해 보겠습니다:

전체 파이프라인이 잘 작동하는 것 같습니다. 물론 예측 성능이 아주 좋지는 않습니다. SVR보다 RandomForestRegressor가 더 나은 것 같습니다.

5.

질문: GridSearchCV를 사용해 준비 단계의 옵션을 자동으로 탐색해보세요.

경고: 사용하는 하드웨어에 따라 다음 셀을 실행하는데 45분 또는 그 이상 걸릴 수 있습니다.

최상의 Imputer 정책은 most_frequent이고 거의 모든 특성이 유용합니다(16개 중 15개). 마지막 특성(ISLAND)은 잡음이 추가될 뿐입니다.