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

inxnxng·2021년 1월 22일
0
  1. 210119
  2. 210121

이미지까지 확인하려면 다음 notion 링크를 확인하자.
링크 : https://www.notion.so/bmo29/2-3-chp-2-c6dba505d0154de2967c25502a542aa2

2.1 실제 데이터로 작업하기

2.2 큰 그림 보기

  • 파이프라인

2.2.1 문제 정의

이 예시는 레이블된 훈련 샘플이 있으니 전형적인 지도 학습 작업으로 접근할 수 있다. 또한 예측에 사용할 특성이 여러개이므로 다중 회귀 ; multiple regression 문제이며, 각 구역마다 하나의 값을 예측하므로 단변량 회귀 ; univariate regression 이다. (구역마다 여러 값을 예측한다고 하면 다변량 회귀 ; multivariate regression 이다.)

마지막으로 이 시스템으로 들어오는 데이터에 연속적인 흐름이 없고 빠르게 변하는 데이터에 적응하지 않아도 되므로 데이터가 메모리에 들어갈 만큼 풍분히 작으므로 일반적인 배치 학습이 적절하다.

2.2.2 성능 측정 지표 선택

회귀 문제의 전형적인 성능 지표는 평균 제곱근 오차 ; root mean square error (RSME) 이다. 오차가 커질수록 이 값은 커지기 때문에 예측에 얼마나 많은 오류가 있는지 알 수 있게 된다.

RMSE(X, h)는 가설 h를 사용하여 일련의 샘플을 평가하는 비용함수이다.

만약 이상치로 보이는 구역이 많으면 이 때는 평균 절대 오차 ; mean absolute error (평균 절대 편차; mean absolute deviation 이라고도 함) 을 고려한다. RMSE가 MAE보다 조금 더 이상치에 민감하기 때문이다.

RSME와 MAE 모두 에측값의 벡터와 타깃값의 벡터 사이의 거리를 재는 방법이다. 거리 측정에는 여러 가지 방법(또는 노름 ; norm)이 가능하다.

2.2.3 가정 검사

올바른 카테고리를 구해야 한다면 회귀가 아니라 분류 작업을 해야 한다.

2.3 데이터 가져오기

import os
import tarfile
import urllib.request

DOWNLOAD_ROOT = "https://raw.githubusercontent.com/rickiepark/handson-ml2/master/"
HOUSING_PATH = os.path.join("datasets", "housing")
HOUSING_URL = DOWNLOAD_ROOT + "datasets/housing/housing.tgz"

def fetch_housing_data(housing_url=HOUSING_URL, housing_path=HOUSING_PATH):
  if not os.path.isdir(housing_path):
    os.makedirs(housing_path)
  tgz_path = os.path.join(housing_path, "housing.tgz")
  urllib.request.urlretrieve(housing_url, tgz_path)
  housing_tgz = tarfile.open(tgz_path)
  housing_tgz.extractall(path=housing_path)
  housing_tgz.close()

fetch_housing_data() 위 함수를 불러와야 데이터를 가져올 수 있다.

import pandas as pd

def load_housing_data(housing_path=HOUSING_PATH):
  csv_path = os.path.join(housing_path, "housing.csv")
  return pd.read_csv(csv_path)

이 함수를 통해 모든 데이터를 담은 판다스의 데이터프레임 객체를 반환받는다.

2.3.3 데이터 구조 훑어보기

.head() , .info() , .value_counts() , .describe() 를 통해 데이터에 접근할 수 있다.

%matplotlib inline
import matplotlib.pyplot as plt
housing.hist(bins=50, figsize=(20,15))
plt.show()

데이터의 형태를 빠르게 검토하기 위해 숫자형 특성을 히스토그램으로 그려볼 수 있다. 히스토그램은 주어진 값의 범위(수평축)에 속한 샘플 수(수직축)를 나타낸다.

2.3.4 테스트 세트 만들기

테스트 세트로 일반화 오차를 추정하면 매우 낙관적인 추정이 되며 시스템을 론칭했을 때 기대한 성능이 나오지 않을 가능성이 높다. 이를 데이터 스누핑 ; data snooping 편향이라고 한다.

따라서 데이터 셋의 20%를 따로 떼어놔야 한다.

import numpy as np

def split_train_test(data, test_ratio):
    shuffled_indices = np.random.permutation(len(data))
			#permutation은 순열 랜덤 시키는데 쓴 것
    test_set_size = int(len(data)*test_ratio)
			#20% 따로 떼어놓는다 하였으므로
    test_indices = shuffled_indices[:test_set_size]
			#indices는 표시 datae set의 20%를 랜덤으로 정렬된 
            		#shuffled_indices에서 가져와 새로운 배열인 
                    	#test_indices에 넣어준다
    train_indices = shuffled_indices[test_set_size:]
			#나머지 80%를 새로운 배열 train_indices에 넣어준다
    return data.iloc[train_indices], data.iloc[test_indices]

.loc 이나 [:] 에 관한 부분은 다음을 참고한다.

참고 : 데이터 인덱싱(loc, iloc, 슬라이싱, 불린인덱싱, at, iat, ix)-pandas(10)

train_set, test_set = split_train_test(housing,0.20) 를 통해 train_set과 test_set에 각각 데이터들을 분배한다.

이렇게 np.random.permutation() 으로 항상 같은 난수 인덱스가 생성되도록 할 수도 있지만 난수 발생기의 초깃값을 설정하여 np.random.seed(42) 로 설정하여 사용할 수도 있다. 하지만 이렇게 되면 매번 동일한 테스트 세트가 유지되므로 다음과 같이 이전 훈련 세트에 있던 샘플을 포함시키지 안도록 만들수도 있다.

from zlib import crc32

def test_set_check(identifier, test_ratio):
    return crc32(np.int64(identifier)) & 0xffffffff < test_ratio * 2**32

def split_train_test_by_id(data, test_ratio, id_column):
    ids = data[id_column]
    in_test_set = ids.apply(lambda id_: test_set_check(id_, test_ratio))
    return data.loc[~in_test_set], data.loc[in_test_set]

행의 인덱스를 ID로 사용하여 식별자 column을 추가할 수 있다. 다만 이 때에는 새 데이터가 데이터 셋의 끝에 추가되어야 하며 어떠한 행도 삭제되면 안된다.

housing_with_id = housing.reset_index()
train_set, test_set = split_train_test_by_id(housing_with_id, 0.2, "index")
housing_with_id["id"] = housing["longitude"] * 1000 + housing["latitude"]

train_set, test_set = split_train_test_by_id(housing_with_id, 0.2, "id")

사이킷런을 이용해 다음과 같이 train_set과 test_set을 나눌 수도 있다.

from sklearn.model_selection import train_test_split

train_set, test_set = train_test_split(housing,
					test_size=0.2, random_state=42)

계층 ; strata 이라는 동질의 그룹으로 표본을 나누고 테스트 세트가 전체 그룹을 대표할 수 있도록 각 계층에서 올바른 수의 샘플을 추출하는 것이 계층적 샘플링 ; strata sampling 이다. 이를 통해 샘플링 편향을 최대한 피하도록 한다.

계층의 중요도를 추정하는데 편향되지 않도록 너무 많은 계층으로 나누면 안되며 각 계층이 충분히 커야 한다. 여기서 중간 소득이 중간 주택 가격을 예측하는데 매우 중요하다 했으므로 새로운 카테고리를 추가하여 더 정확한 주택 가격 예측을 해보자.

housing["income_cat"] = pd.cut(housing["median_income"],
			bins=[0., 1.5, 3.0, 4.5, 6., np.inf],
            		labels=[1, 2, 3, 4, 5])

housing["income_cat"].hist()

.cut 을 통해 카테고리를 5개 가진 소득 카테고리 특성을 만든다. label은 1~5를 가지며 카테고리 1은 0에서 1.5까지의 범위를, 카테고리 2는 1.5에서 3.0까지 범위를 갖는다.

사이킷런의 Stratified ShuffleSplit을 사용하여 정리한다면,

from sklearn.model_selection import StratifiedShuffleSplit

split = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)
for train_index, test_index in split.split(housing, housing["income_cat"]):
    strat_train_set=housing.loc[train_index]
    strat_test_set=housing.loc[test_index]

strat_test_set["income_cat"].value_counts() / len(strat_test_set) 을 통해 테스트 세트에서의 소득 카테고리 비율을 확인할 수 있다.

for set_ in (strat_test_set, strat_train_set):
    set_.drop("income_cat", axis=1,inplace=True)

을 통해 income_cat 특성을 삭제하여 데이터를 원래 상태로 되돌린다. .drop() 은 행 또는 열을 삭제하는데 axis가 0이면 행을, 1이면 열을 삭제한다. inplace를 True로 설정하면 호출된 데이터 프레임 자체를 수정하고 아무런 값도 반환하지 않는다. (inplace가 대체한다는 뜻인 것을 생각)

2.4 데이터 이해를 위한 탐색과 시각화

2.4.1 지리적 데이터 시각화

housing.plot(kind="scatter", x="longitude", y ="latitude")

housing.plot(kind="scatter", x="longitude", y ="latitude", alpha=0.1)

x와 y에는 어떤 값이 들어가야 하는지 설정한 것이므로 임의로 이름을 줄 수 있는 옵션이 아니다. alpha 옵션을 통해 데이터 포인트가 밀집된 영역을 확인할 수 있다.

housing.plot(kind="scatter", x="longitude", y="latitude", alpha=0.4,
    s=housing["population"]/100, label="population", figsize=(10,7),
    c="median_house_value", cmap=plt.get_cmap("jet"), colorbar=True,
    sharex=False)
plt.legend()

2.4.2 상관관계 조사

데이터 셋이 매우 크지 않다면 모든 특성간의 표준 상관계수 ; standard correlation coefficient (피어슨의 rr이라고도 부름) 를 corr() 로 계산할 수 있다.

corr_matrix = housing.corr()

중간 주택 가격 ; median_house_value 를 기준으로 1에 가까우면 강한 양의 상관관계를 가지고 (중간 소득이 증가할 때 주택 가격도 같이 증가한다.) -1에 가까우면 강한 음의 상관관계를 가진다. (북쪽으로 갈 수록 주택 가격 하락.) 0에 가까우면 선형적인 상관관계가 없음을 알 수 있다.

from pandas.plotting import scatter_matrix

attr = ["median_house_value", "median_income", 
	"total_rooms", "housing_median_age"]
scatter_matrix(housing[attr], figsize=(12,8))

대각선으로는 자기 자신과의 비교이다. 따라서 기본 설정된 그래프가 나온다.

중간 주책 가격을 예측하는데 가장 유용할 것 같은 특성은 중간 소득이므로(피어슨의 상관계수 1의 모양에 가장 비슷하므로) 상관관계 산점도를 확대해보면 몇 가지 사실을 확인할 수 있다.

  1. 상관관계가 매우 강하다. 위쪽으로 향하는 경향을 확인할 수 있으며 포인트들이 너무 분산되어 있지 않다.
  2. 앞서 본 가격 제한값인 $50,000 근처에서 수평선을 확인할 수 있다. 이러한 수평선으로 나타나는 값들은 제거하는 것이 좋다.

housing.plot(kind="scatter", x="median_income", y="median_house_value", alpha=0.1)

2.4.3 특성 조합으로 실험

데이터의 조합을 여러 특성의 조합으로 만들어 진짜 필요한 특성들을 얻고 필요 없는 특성은 없앤다. 특히 머신러닝 프로젝트는 빠른 프로토타이핑과 반복적인 프로세스가 권장된다.

2.5 머신러닝 알고리즘을 위한 데이터 준비

데이터를 준비할 때에도 수동으로 하지 말고 함수를 만들어 자동화하는 것이 좋다.

2.5.1 데이터 정제

.dropna() 를 통해 해당 구역을 제거하거나 , .drop() 를 통해 전체 특성을 지우고 , .fillna() 를 통해 어떤 값으로 채워 특성에 값이 없는 경우를 처리한다.

다음과 같이 설정하여 누락된 값을 중간값으로 설정할 수 있다.

median = housing["total_bedrooms"].median()
sample_incomplete_rows["total_bedrooms"].fillna(median, inplace=True) # 옵션 3
from sklearn.impute import SimpleImputer
imputer = SimpleImputer(strategy="median")

중간값은 수치형 특성에서만 계산될 수 있으므로 텍스트 특성인 ocean_proximity를 제외한 데이터 복사본으로 계산을 진행한다.

housing_num = housing.drop("ocean_proximity", axis=1)
# 다른 방법: housing_num = housing.select_dtypes(include=[np.number])
imputer.fit(housing_num)

imputer.fit(housing_num) 를 통해 훈련데이터에 적용한다.

변형된 특성들이 들어있는 넘파이 배열(X)을 판다스 데이터 프레임(housing_tr)으로 되돌리면,

X = imputer.transform(housing_num)
housing_tr = pd.DataFrame(X, columns=housing_num.columns, index=housing_num.index)

2.5.2 텍스트와 범주형 특성 다루기

텍스트 범주로 되어있는 특성을 숫자로 변환하기 위해,

from sklearn.preprocessing import OrdinalEncoder
ordinal_encoder=OrdinalEncoder()
housing_cat_encoded=ordinal_encoder.fit_transform(housing_cat)

한 특성만 1이고(핫) 나머지는 0인 특성을 갖도록 이진 특성을 만드는 것이 원-핫 인코딩 ; one-hot encoding 이라고 한다.

from sklearn.preprocessing import OneHotEncoder

cat_encoder = OneHotEncoder()
housing_cat_1hot = cat_encoder.fit_transform(housing_cat)

이렇게 하면 넘파이 배열이 아닌 사이파이 ; SciPy 희소 행렬 ; sparse matrix 로 나온다. 수천 개의 특성이 있는 범주형 특성일 경우 매우 효과적인데 원-핫 인코딩을 통해 열이 수천 개인 행렬로 변한다. 여기에 각 행은 1이 하나 뿐이고 그 외에는 모두 0으로 채워져 있는데, 0을 모두 메모리에 저장하는 것은 낭비이므로 희소 행렬은 0이 아닌 원소의 위치만 저장하여 일반적인 2차원 배열처럼 사용할 수 있다.

.categories_ 로는 인스턴스 변수에 접근하여 카테고리 리스트를 얻을 수 있지만 .categories 로는 카테고리의 유형만 얻을 수 있다.

2.5.3 나만의 변환기

파이썬에는 이름에 Mixin이 있으면 객체의 기능을 확장하려는 목적으로 만들어진 클래스를 나타낸다. TransformerMixinfit_transform() 메서드는 단순히 fit()transform() 을 메서드 연결 ; method chaining한다.

아직 완벽히 이해하지 못했다.

from sklearn.base import BaseEstimator, TransformerMixin

rooms_ix, bedrooms_ix, population_ix, households_ix = 3,4,5,6

class CombinedAttributesAdder(BaseEstimator, TransformerMixin) :
    def __init__(self, add_bedrooms_per_room = True):
        self.add_bedrooms_per_room = add_bedrooms_per_room
    def fit(self, X, y =None):
        return self
    def transform(self, X):
        rooms_per_household = X[:, rooms_ix] / X[:, households_ix]
        population_per_household = X[:, population_ix] / X[:, households_ix]
        if self.add_bedrooms_per_room :
            bedrooms_per_room = X[:, bedrooms_ix] / X[:, rooms_ix]
            return np.c_[X, rooms_per_household, population_per_household, bedrooms_per_room]
        else:
            return np.c_[X, rooms_per_household, population_per_household]

attr_adder = CombinedAttributesAdder(add_bedrooms_per_room=False)
housing_extra_attribs = attr_adder.transform(housing.to_numpy())
  • 책에서는 이렇게 했지만..
    변환기가 add_bedrooms_per_room 하이퍼파라미터 하나를 가지며 기본값은 True로 받는다. 100% 확신이 없는 모든 데이터 준비 단계에 대해 하이퍼파라미터를 추가할 수 있다. 즉 데이터 준비 단계를 자동화하여 더 많은 조합을 시도해볼 수 있다는 장점이 있다.

2.5.4 특성 스케일링

특성 스케일링 ; feature scaling 을 통해 입력 숫자 특성의 스케일을 맞춰놔야 한다. 모든 특성의 범위를 같도록 만들어주는 방법으로 min-max 스케일링표준화 ; standardization 이 쓰인다.

min-max 스케일링정규화 ; normalization 이라고도 불린다. 이는 0~1 범위에 들도록 값을 이동하고 스케일링을 조정하는 것이다. 데이터에서 최솟값을 뺀 후 최댓값과 최솟값의 차이로 나눠야 하는데 이는 사이킷런에서 MinMaxScaler 변환기를 이용할 수 있다. feature_range 매개변수를 통해 0~1 외의 범위로 조절할 수도 있다.

표준화는 방법이 다르다. 평균을 뺀 후 (그렇기에 표준화를 진행하면 평균은 항상 0이 된다) 표준편차로 나누어 결과 분포의 분산이 1이 되도록 한다. 표준화는 이로 인해 범위의 상한과 하한이 없어 신경망과 같이 입력값의 범위를 0에서 1사이로 기대하는 알고리즘에서는 사용할 수 없다. 그러나 표준화는 이상치에 영향을 덜 받는다. 사이킷런에서 StandardScaler 변환기를 사용한다.

모든 변환기에서의 스케일링은 전체 데이터 세트를 대상으로 하지 않고 훈련 데이터에 대해서만 fit() 메서드를 적용한다. 그런 다음 훈련 세트와 테스트 세트(그리고 새로운 데이터)에 대해서는 transform() 메서드를 사용한다.

2.5.2 변환 파이프라인

변환 단계가 많고 정확한 순서대로 진행되어야 하므로 연속된 변환을 순서대로 처리할 수 있는 Pipeline 클래스를 이용하여 수사 특성을 처리할 수 있게 하자.

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

num_pipeline = Pipeline([
    ('imputer', SimpleImputer(strategy="median")),
    ('attribs_adder', CombinedAttributesAdder()),
    ('std_scaler', StandardScaler()),
])

housing_num_tr = num_pipeline.fit_transform(housing_num)

Pipeline 은 연속된 단계를 나타내는 이름/추정기 쌍의 목록을 입력으로 받는다.

수치로 정렬되어 있던 housing_num을 변환과정을 통해 모두 표준화?하여 자료를 손질하였다.

사이킷런의 ColumnTransformer 클래스를 사용해 주택 가격 데이터에 전체 변환을 적용하면,

from sklearn.compose import ColumnTransformer

num_attribs = list(housing_num)
cat_attribs = ["ocean_proximity"]

full_pipeline = ColumnTransformer([
        ("num", num_pipeline, num_attribs), #위의 그 num_pipeline이 맞다.
        ("cat", OneHotEncoder(), cat_attribs),
    ])

housing_prepared = full_pipeline.fit_transform(housing)

수치형 열 이름의 리스트와 범주형 열 이름의 리스트를 만들고 클래스 객체를 만들어 생성자로 튜플의 리스트를 받는다. 수치형 열은 num_pipeline을 통해 변환되고(밀집 행렬을 반환) 범주형 열은 OneHotEncoder을 사용되어 변환된다(희소 행렬을 반환).

이렇게 희소 행렬과 밀집 행렬이 섞여잇다면 ColumnTransformer는 최종 행렬의 밀집 정도를 추정한다. 밀집도가 임곗값(기본적으로 0.3)보다 낮으면 희소 행렬을 반환한다.

2.6 모델 선택과 훈련

2.6.1 훈련 세트에서 훈련하고 평가하기

from sklearn.linear_model import LinearRegression

lin_reg = LinearRegression()
lin_reg.fit(housing_prepared, housing_labels)

선형 회귀 모델을 훈련시킨다.

훈련 세트에 있는 5개의 샘플에 대해 적용한다.

사이킷런의 mean_square_error 함수를 이용해 전체 훈련 세트에 대한 이 회귀 모델의 RMSE를 측정한다.

from sklearn.metrics import mean_squared_error

housing_predictions = lin_reg.predict(housing_prepared)
lin_mse = mean_squared_error(housing_labels, housing_predictions)
lin_rmse = np.sqrt(lin_mse)

오차가 너무 크다. 이는 모델이 훈련 데이터에 과소적합; underfit 된 사례이다.

DecisionTreeRegressor 를 통해 강력하고 데이터에서 복잡한 비선형 관계를 찾아보자.

from sklearn.tree import DecisionTreeRegressor

tree_reg = DecisionTreeRegressor(random_state=42)
tree_reg.fit(housing_prepared, housing_labels)
housing_predictions = tree_reg.predict(housing_prepared)
tree_mse = mean_squared_error(housing_labels, housing_predictions)
tree_rmse = np.sqrt(tree_mse)

오차가 전혀 없는 것은 말이 안된다. 모델이 데이터에 너무 심하게 과대적합 ; overfit된 것이다.

5개의 예시로 진행하였기 때문에 문제가 많이 생기는 것이다. 계속해서 훈련 세트의 일부분으로 훈련하고 다른 부분인 테스트 세트는 건드리지 말아야 한다.

2.6.2 교차 검증을 사용한 평가

사이킷런의 k-겹 교차 검증 ; k-fold cross-validation 을 사용하여 검증 세트로 모델을 평가해보자. 훈련 세트를 폴드 ; fold 라고 부르는 10개의 서브셋으로 무작위 분할하고 결정 트리 모델을 10번 훈련하고 평가하는데 매번 다른 폴드를 선택해 평가에 사용하고 나머지 9개의 폴드는 훈련에 사용한다. 이렇게 되면 10개의 평가 점수가 담긴 배열이 결과과 된다.

from sklearn.model_selection import cross_val_score

scores = cross_val_score(tree_reg, housing_prepared, housing_labels,
                         scoring="neg_mean_squared_error", cv=10)
tree_rmse_scores = np.sqrt(-scores)

scoring 매개 변수에 낮을 수록 좋은 비용함수가 아닌 클수록 좋은 효용함수를 넣어야 한다. 따라서 평균 제곱 오차 ; MSE의 반댓값 (제곱의 반댓값이므로 음수)을 계산하는 neg_mean_squared_error 함수를 사용한다.

여러 다른 모델을 모아서 하나의 모델을 만드는 것을 앙상블 학습이라고 하며 머신러닝 알고리즘의 성능을 극대화한다.

from sklearn.ensemble import RandomForestRegressor

forest_reg = RandomForestRegressor(n_estimators=100, random_state=42)
forest_reg.fit(housing_prepared, housing_labels)

housing_predictions = forest_reg.predict(housing_prepared)
forest_mse = mean_squared_error(housing_labels, housing_predictions)
forest_rmse = np.sqrt(forest_mse)
from sklearn.model_selection import cross_val_score

forest_scores = cross_val_score(forest_reg, housing_prepared, housing_labels,
                                scoring="neg_mean_squared_error", cv=10)
forest_rmse_scores = np.sqrt(-forest_scores)
display_scores(forest_rmse_scores)

실험한 모델을 모두 저장해두면 필요할 때 쉽게 모델을 복원할 수 있다.

import joblib

joblib.dump(my_model, "my_model.pkl")

#나중에
my_model_loaded=joblib.load("my_model.pkl")

2.7 모델 세부 튜닝

2.7.1 그리드 탐색

가능한 모든 하이퍼파라미터 조합에 대해 교차 검증을 사용해 평가한다.

from sklearn.model_selection import GridSearchCV

param_grid = [
							# 12(=3×4)개의 하이퍼파라미터 조합을 시도
              {'n_estimators':[3,10,30], 'max_features': [2,4,6,8]},
							# bootstrap은 False로 하고 6(=2×3)개의 조합을 시도
              {'bootstrap': [False], 'n_estimators':[3,10], 'max_features': [2,3,4]},
         ]

forest_reg=RandomForestRegressor(random_state=42)

# 다섯 개의 폴드로 훈련하면 총 (12+6)*5=90번의 훈련이 일어납니다.
grid_search=GridSearchCV(forest_reg, param_grid, cv=5, scoring='neg_mean_squared_error',return_train_score=True)

grid_search.fit(housing_prepared, housing_labels)

cv=5 를 통해 5-겹 교차 검증을 사용한다는 것을 명시할 수 있다.

RandomForestRegressor 객체를 생성할 때, random_state를 설정하지 않으면 max_features가 6이 나온다.

여기서 최솟값인 49682.~~ 을 나타내는 max_features 하이퍼파라미터가 8, n_estimators 하이퍼파라미터가 30일 때가 최적의 솔루션이다. 보다싶이 총 18개의 조합으로 훈련한 것을 확인할 수 있다.

2.7.2 랜덤 탐색

많은 수의 조합을 탐구할 때, RandomizedSearchCV를 사용하는 것이 좋다.

2.7.3 앙상블 방법

💚

2.7.4 최상의 모델과 오차 분석

💚

2.7.5 테스트 세트로 시스템 평가하기

테스트 세트에서 예측 변수와 레이블을 얻을 수 full_pipeline 을 사용하여 데이터를 변환하고 테스트 세트에서 최종 모델을 평가한다.

final_model = grid_search.best_estimator_

X_test = strat_test_set.drop("median_house_value", axis=1)
y_test = strat_test_set["median_house_value"].copy()

X_test_prepared = full_pipeline.transform(X_test) #fit_transform()이 아닌 transform()
final_predictions = final_model.predict(X_test_prepared)

final_mse = mean_squared_error(y_test, final_predictions)
final_rmse = np.sqrt(final_mse)

추정값이 얼마나 정확한지 알기 위해 scipy.stats.t.interval() 를 사용하여 일반화 오차의 95% 신뢰 구간 ; confidence interval 을 계산할 수 있다.

from scipy import stats

confidence = 0.95
squared_errors = (final_predictions - y_test) ** 2
np.sqrt(stats.t.interval(confidence, len(squared_errors) - 1,
                         loc=squared_errors.mean(),
                         scale=stats.sem(squared_errors)))

2.8 론칭, 모니터링, 시스템 유지 보수

0개의 댓글