본문 바로가기
컴퓨터공학/AI

기계 학습 2.프로젝트 진행 과정

by Jinger 2023. 9. 18.

서론

    기계학습이 만들어지는 일반적인 흐름을 살펴보며 기계학습에 대한 이해를 높여보자.


과정

  1. 큰 그림 보기(Look at the big picture.)
  2. 데이터 가져오기(Get the data.)
  3. 데이터 시각화로 통찰력 갖기(Discover and visualize the data to gain insights.)
  4. 머신 러닝을 위한 데이터 준비(Prepare the data for Machine Learning algorithms.)
  5. 학습 모델 선정(Select and train a model.)
  6. 모델 조정(Fine-tune your model.)
  7. 출시 및 관리, 유지 보수(Launch, monitor, and maintain your system.)

큰 그림 보기

문제 정의

    머신러닝 모델을 구축하는 것이 목표가 아니다. 회사가 이 모델을 어떻게 활용하고 어떤 이점을 얻고자 하는지를 파악하는 것이 중요하다. 이 목표를 이해하는 것은 문제를 어떻게 구성할지, 어떤 알고리즘을 선택할지, 모델을 평가할 때 어떤 성능 측정 지표를 사용할지, 그리고 모델을 조율하는 데 얼마나 많은 노력을 기울일지를 결정된다.

모델선정

    머신 러닝 모델을 구성하기 위해서는 현재 상황을 고려하여 다음과 같은 요소들을 결정해야 한다. 먼저, 지도 학습, 비지도 학습, 또는 강화 학습 중에서 어떤 유형의 학습을 사용할 것인지를 결정해야 한다. 그다음으로, 이 문제가 분류, 회귀, 또는 다른 유형의 작업인지를 식별해야 한다. 마지막으로, 배치 학습 또는 온라인 학습 중에서 어떤 학습 모델을 선택할 것인지를 결정해야 한다.

성능 측정 지표

    성능 측정 지표를 선택하는 것은 회귀 문제에서 일반적으로 사용되는 Root Mean Square Error (RMSE)로 수행된다. RMSE는 다음과 같이 정의됩니다.

RMSE

  • 𝑚: 데이터셋의 인스턴스 수
  • 𝐱(𝑖): 데이터셋의 𝑖번째 인스턴스의 레이블을 제외한 모든 피처 값들로 구성된 벡터
  • 𝑦(𝑖): 데이터셋의 𝑖번째 인스턴스의 레이블(해당 인스턴스에 대한 원하는 출력값)
  • 𝐗: 모든 인스턴스의 피처 값(레이블 제외)으로 구성된 행렬. 각 행은 하나의 인스턴스에 대응하며, 𝑖번째 행은 𝐱(𝑖)의 전치로, 𝐱(𝒊) 𝑇로 표시
  • ℎ: 시스템의 예측 함수, 또는 가설.

    RMSE(𝐗, ℎ)는 가설 ℎ를 사용하여 데이터 예제 집합에서 측정한 비용 함수를 나타낸다. 회귀 작업에 대한 RMSE는 일반적으로 선호되지만, 특정 맥락에서 다른 함수를 사용하기를 원할 수도 있다. 예를 들어, 이상치 지역이 많은 경우 평균 절대 오차(MAE, Mean Absolute Error, 평균 절대 편차라고도 함)를 사용하는 것이 더 적절할 수 있다.

MAE

    RMSE 및 MAE는 두 벡터 사이의 거리를 측정하는 방법이며, 다양한 거리 측정 또는 표준(norms, 노름)이 가능합니다. 제곱의 합의 제곱근을 계산하는 것 (RMSE)은 유클리드 노름(Euclidean norm)에 해당한다. 이것은 ℓ2-norm이라고도 합니다. 절댓값의 합을 계산하는 것 (MAE)은 ℓ1-norm 해당한다. 이것은 맨하탄 노름이라고도 한다. 노름 인덱스가 높을수록 큰 값에 더 중점을 두고 작은 값을 무시한다. 이것은 RMSE가 MAE보다 이상치에 민감하기 때문이다. 그러나 이상치가 지수적으로 드물 경우 (종 모양 곡선과 같이), RMSE는 매우 잘 수행되며 일반적으로 선호된다.

가정확인

    마지막으로, 지금까지 한 가정을 나열하고 확인하는 것이다. 즉, 가정을 명확하게 나열하고 문제 정의를 검토하여 모델링 및 문제 해결 방향을 미리 파악하고, 후속 시스템과의 통합을 고려하는 것이 중요한 사항이다.

데이터 가져오기

    일반적으로 관계형 데이터 베이스(relational database) 즉, 테이블과 같은 형태로 저장이 되어 있다. 작은 데이터 셋 같은 경우에는 .csv파일로 저장이 되어 있다.

// url로 가져오기
import os
import tarfile
import urllib

DOWNLOAD_ROOT = "https://raw.githubusercontent.com/ageron/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):
    os.makedirs(housing_path, exist_ok=True)
    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()
    
// csv파일 가져오기
import pandas as pd

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

데이터 구조 살펴보기

    데이터프레임(DataFrame)의 head() 메서드를 사용하여 상위 다섯 개 행을 확인할 수 있다.

 housing = load_housing_data()
 housing.head()

     info() 메서드데이터의 간단한 설명을 얻는 데 유용하다. 특히 전체 행 수, 각 속성의 유형 및 비 널(non-null) 값 수를 확인할 수 있다. 예시에 있는 housing 데이터셋에는 20,640개의 인스턴스가 있다. 그러나 total_bedrooms 속성에는 20,433개의 비 널 값만 있으므로 207개의 지구가 이 기능이 누락되었다는 것을 의미한다. 이러한 누락을 우선 확인하기 위해 확인이 필요하다. 또한, 모든 속성은 숫자이지만 ocean_proximity 필드는 숫자가 아니다. ocean_proximity 필드의 유형은 객체(object)이므로 Python 객체의 어떤 종류도 될 수 있지만 CSV 파일에서 이 데이터를 로드했으므로 텍스트 속성임을 알 수 있다. 상위 다섯 개 행을 살펴본 결과 ocean_proximity 열의 값이 반복되는 것을 알 수 있으므로 이것은 범주형 속성일 가능성이 높다. 각 범주에 어떤 지역이 속하는지와 해당 범주에 속하는 지구 수를 확인하려면 value_counts() 메서드를 사용할 수 있다.

housing.info()

housing["ocean_proximity"].value_counts()

   또 다른 데이터의 유형을 파악하는 빠른 방법은 각 숫자 속성에 대한 히스토그램을 그려보는 것이다. 불필요한 데이터를 상한선과 하한선을 통해 특정 교육 세트 및 테스트 세트를 제거하기도 한다. 히스토그램에서 주의를 가져야 할 점은 각각 데이터의 모든 속성은 서로 다른 스케일을 가지고 있을 수 있다. 마지막으로, 많은 히스토그램은 테일 헤비(tail-heavy)해질 수 있다. 이는 일부 머신 러닝 알고리즘이 패턴을 감지하기 어렵게 만들 수 있다. 이러한 속성을 나중에 더 벨 모양( bell-shaped) 분포를 갖도록 변환해 보자.

# 표
housing.describe()
# 히스토그램
%matplotliv inline	# only in a Jupyter notebook
import matplotliv.pyplot as plt
housing.hist(bins=50, figsize=(20.15))
plt.show()

테스트 세트 만들기

    테스트 세트를 만들기 위해 몇 가지 주의해야 할 사항이 있다. 먼저, 인간의 뇌는 패턴 감지에 뛰어나며, 테스트 세트를 미리 살펴본다면 테스트 데이터에서 흥미로운 패턴을 우연히 발견하여 특정 유형의 머신 러닝 모델을 선택하게 될 수 있다. 이 경우, 테스트 세트를 사용하여 일반화 오차를 추정할 때 추정이 너무 낙관적일 것이며, 예상보다 성능이 좋지 않은 시스템을 시작하게 될 것이다. 이를 데이터 스누핑 편향(data snooping bias)이라고 한다.
    테스트 세트를 생성하기 위해서는 보통 데이터셋의 일부를 무작위로 선택하며, 일반적으로 데이터셋의 20%를 선택한다. (데이터셋이 매우 크다면 더 적은 비율로 선택할 수도 있다). 그러나 코드를 여러 번 실행하면 다른 테스트 세트가 생성될 수 있기 때문에 문제가 있다. 이러한 문제를 해결하기 위한 몇 가지 방법이 있다.

  • 처음 실행할 때 테스트 세트를 저장하고, 이후 실행에서는 해당 테스트 세트를 로드한다.
  • np.random.permutation()을 호출하기 전에 난수 생성기의 시드(seed)를 설정하여 항상 같은 섞인 인덱스를 생성한다.
  • 각 인스턴스의 식별자를 사용하여 해당 인스턴스가 테스트 세트로 들어가야 하는지 여부를 결정한다(인스턴스가 고유하고 변경 불가능한 식별자를 가지고 있다고 가정).
# test set 생성
import numpy as np

def split_train_test(data, test_ratio):
    shuffled_indices = np.random.permutation(len(data))
    test_set_size = int(len(data) * test_ratio)
    test_indices = shuffled_indices[:test_set_size]
    train_indices = shuffeld_indices[test_set_size:]
    return data.iloc[train_indices], data.iloc[test_indices]

     무작위 샘플링 방법을 고려해 왔다. 데이터셋이 충분히 크면(특히 속성 수에 비해 충분히 큰 경우) 일반적으로 괜찮지만 그렇지 않은 경우 표집 편향을 도입할 위험이 있다. 예를 들어 미국 인구는 51.3%가 여성이고 48.7%가 남성이므로 미국에서 잘 수행된 조사는 이 비율을 유지하려고 노력할 것입니다(1,000명의 조사 대상에서 513명의 여성과 487명의 남성). 이를 계층 샘플링(stratified sampling)이라고 하며, 인구를 동질의 하위 그룹인 계층으로 나누고 각 계층에서 적절한 수의 인스턴스를 샘플링하여 테스트 세트가 전체 인구를 대표하도록 보장한다.

데이터 시각화로 통찰력 갖기

데이터 탐색, 시각화로 통찰력을 갖기 이전

     테스트 세트를 따로 떼어놓고 훈련 세트만 탐색해야 한다. 또한 훈련 세트가 매우 크다면 조작을 쉽고 빠르게 하기 위해 탐색 세트를 샘플링하는 것이 좋을 수 있다. 데이터를 시각화하여 살펴보자.

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

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

상관관계 찾기

    데이터셋이 크지 않으면 모든 속성 간의 표준 상관 계수 (피어슨 상관 계수라고도 함, Pearson’s r)를 계산할 수 있다. 상관 계수는 선형 상관관계만을 측정한다. 

corr_matrix = housing.corr()
corr_matrix["median_house_value"].sort_values(ascending=False)

    선형 관계만 측정을 하게 되면 위 예시 그림의 최상단과 같은 경우에는 문제가 없지만, 그다음 줄에 있는 상관관계가 인간의 눈에는 보이지만, 코드 상으로는 알기 힘들 수 있다. 그럼에도 연관성을 쉽게 판단을 할 수 있기에 널리 사용된다.
   각 수치 속성을 다른 모든 수치 속성에 대해 플롯하여 각 속성 당 연관성을 확인할 수 있다.

from pandas.plotting import scatter_matrix

attributes = ["median_house_value", "median_income", "total_rooms", "housing_median_age"]
scatter_matrix(housing[attributes], figsize=(21,8))

    기계 학습 알로리즘의 데이터 준비 전 마지막으로 해야 할 일은 다양한 속성 조합을 시도하는 것이다. 

housing["rooms_per_household"] = housing["total_rooms"]/housing["households"]
housing["bedrooms_per_room"] = housing["total_bedrooms"]/housing["total_rooms"]
housing["population_per_household"]=housing["population"]/housing["households"]

corr_matrix = housing.corr()
corr_matrix["meadian_house_value"].sort_values(ascending=False)

    예시로 위 코드를 작동한 결과를 살펴보자. "Median_house_value"는 본인이기에 1이며 1과 가까우면 해당 수치에 긍정적인 영향을 -1과 가까워지면 부정적인 영향을 준다. "total_rooms"와 "total_bedrooms"을 보면 0에 가깝다. 하지만, 이 둘을 합쳐 "Median_house_value"와의 연관성을 찾아보니 "bedrooms_per_room" 이전 두 데이터 보다 더 큰 영향력을 준다는 것을 알 수 있다. 이 처럼 여러 속성 조합 시도를 통해 원하는 값과의 연광성을 찾아보아야 한다.

머신 러닝을 위한 데이터 준비

데이터 클리닝(Data Cleaning)

    데이터 클리닝은 머신 러닝 프로젝트에서 중요한 과정 중 하나로, 데이터를 정제하고 결측값을 처리하는 작업을 포함한다. 이를 위해 다음과 같은 단계를 따른다.

  1. 예측 변수와 레이블을 분리한다.
  2. 결측값을 처리한다.
    1. 예를 들어, "total_bedrooms" 특성에 결측값이 있는 경우 이를 해결해야 한다. 해당 지역을 제거(option 1), 전체 특성을 삭제(option 2), 결측값을 어떤 값(예: 0, 평균, 중앙값 등)으로 설정(option 3)한다.
housing = start_train_set.drop("median_house_value",axis=1)
housing_labels = start_train_set["median_house_value"].copy()

housing.dropna(subset=["total_bedrooms"])	# option 1
housing.drop("total_bedrooms", axis-1)		# option 2
median = housing["total_bedrooms"].median()	# option 3
housing["tiotal_bedrooms"].fillna(median, inplace=True)

    또한 Scikit-Learn은 결측값 처리를 위한 편리한 클래스인 SimpleImputer를 제공한다. 이 클래스를 사용하여 결측값을 채울 수 있으며, 다음과 같은 전략(strategy)을 사용할 수 있다.

  • "mean": 평균값으로 결측값을 채운다.
  • "most_frequent": 가장 빈번한 값으로 결측값을 채운다.
  • "constant": 사용자가 지정한 값으로 결측값을 채운다.
from sklearn.impute import SimpleImputer

imputer =simpleImputer(strategy="median")
housing_num = houing.drop("ocean_proximity", axis=1)
imputer.fit(housing_num)

imputer.statistics_
housing_num.median().values

X = imputer.transform(housing_num)

    또한 sklearn.impute 패키지에는 수치형 특성에 대한 결측값 처리를 위한 다른 도구들도 있다. KNNImputer은 각 결측값을 해당 특성에 대한 k-최근접 이웃의 값의 평균으로 대체한다. IterativeImputer은 각 특성에 대한 결측값을 다른 모든 사용 가능한 특성을 기반으로 예측하는 회귀 모델을 학습하여 대체한다. 이러한 도구들을 사용하여 데이터를 정제하고 결측값을 처리하여 머신 러닝 모델을 더 정확하게 훈련시킬 수 있다.

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

    예시의 데이터셋에서는 "ocean_proximity" 특성 하나만 텍스트 특성으로 존재한다. 이것은 임의의 텍스트가 아니라 제한된 수의 가능한 값이 있으며 각 값은 범주를 나타낸다. 따라서 이 특성은 범주형 특성이다.
    이러한 범주를 텍스트에서 숫자로 변환해야 한다. 그러나 이 표현 방식은 머신 러닝 알고리즘들이 두 가까운 값이 두 먼 값보다 더 유사하다고 가정한다는 문제가 있다. 이를 해결하기 위해 각 범주에 대한 이진 특성을 만들어서 머신 러닝 알고리즘이 각 범주를 독립적으로 고려할 수 있도록 할 수 있다. 이를 "원-핫 인코딩"(one-hot encoding)이라고 한다.
    원-핫 인코딩을 수행하면 수천 개의 열을 가진 행렬이 생성되며, 대부분의 값이 0인 행렬이 된다. 하지만 수천 개의 범주를 저장하는 데 메모리를 많이 사용하는 것은 낭비적일 수 있다. 이런 경우를 위해 "희소 행렬"(Sparse matrix)이라는 개념을 사용한다. 희소 행렬은 0이 아닌 요소의 위치만 저장하여 메모리를 절약한다. 따라서 텍스트와 범주형 특성을 다루기 위해 원-핫 인코딩을 사용하고, 이를 희소 행렬로 표현하여 효율적으로 메모리를 관리할 수 있습니다.

특성 스케일링과 변환

    데이터에 적용해야 하는 가장 중요한 변환 중 하나는 특성 스케일링(feature scaling)이다. 대부분의 머신 러닝 알고리즘은 입력된 수치 특성이 매우 다른 스케일을 가질 때 잘 동작하지 않는다. 예를 들어, 주택 데이터에서는 방의 총 수가 약 6부터 39,320까지 범위를 가지는 반면, 중간 소득은 0부터 15까지의 범위만을 가진다. 주의할 점은 대상 값(레이블)을 스케일링할 필요가 일반적으로 없다는 것이다. 특성 스케일링을 동일한 스케일을 가진 모든 특성으로 만들기 위해 주로 두 가지 방법을 사용한다.

  • 최소-최대 스케일링(정규화, min-max scaling, normalization): 특성의 값 범위를 0에서 1 사이로 조정(매핑)한다. 이는 `Min-Max 스케일링` 또는 `정규화`라고도 한다.
  • 표준화(standardization): 각 특성에서 평균값을 뺀 후, 표준 편차로 나누어 평균이 0이고 분산이 1이 되도록 만든다. 이렇게 하면 특성이 표준 정규 분포를 따르게 된다.
# min-max scaling(=normaliztion)
from sklearn.preprocessing import MinMaxScaler

min_max_scaler = MinMaxScaler(feature_range=(-1,1))
housing_num_min_max_scaled = min_max_scaler.fit_transform(housing_num)

#standardiztion
from sklearn.preprocessing import StandardScaler

std_scaler = StandardScaler()
housing_num_std_scaled = std_scaler.fit_transform(hosuing_num)

    특성 스케일링을 통해 머신 러닝 알고리즘이 각 특성을 동일한 스케일로 처리하도록 보장할 수 있다. 또한, 특성이 heavy tail을 가지고 있는 경우(즉, 평균에서 멀리 떨어진 값이 지수적으로 드물지 않은 경우), 특성 스케일링 전에 특성을 변환하여 heavy tail을 축소하고 분포를 대략적으로 대칭적으로 만드는 것이 좋다. 예를 들어, 아래 좌측의 그래프에 heavy tail가 우측에 있다면 양수 특성의 경우 제곱근을 취하거나 0과 1 사이의 값으로 만드는 것이 도움이 될 수 있다. 혹은 특성이 매우 긴 heavy tail을 가진 경우 로그 변환을 사용할 수도 있다.

    heavy tail을 가진 특성을 처리하는 또 다른 방법은 특성을 버킷으로 나누는 것이다. 특성의 분포를 대략적으로 동일한 크기의 버킷으로 나누고, 각 특성 값을 해당 버킷의 인덱스로 대체한다. 특성이 다중 모드 분포(즉, 두 개 이상의 명확한 피크가 있는 경우)를 가진 경우, 버킷으로 나누는 것도 도움이 될 수 있지만, 이번에는 버킷 ID를 범주로 다루어야 한다. 이를 위해 원핫인코딩(OneHotEncoder)과 같은 방법으로 버킷 인덱스를 인코딩해야 한다.

사용자 정의 변환기

    데이터 변환 중에 훈련이 필요하지 않은 변환에 대해서는 NumPy 배열을 입력으로 받아 변환된 배열을 출력하는 함수를 작성할 수 있다.

더보기

    예를 들어, 로그 변환기를 만들고 적용할 수 있다. 또한 가우시안 RBF 유사성 측정치를 계산하거나 특성을 결합하는 사용자 정의 변환기를 작성할 수 있다.

# create log-transformer and apply it
form sklearn.preprocessing import FunctionTransformer

log_transformer = FunctionTransformer(np.log, inverse_func=np.exp)
log_pop = log_transformer.transform(housing[["population"]])

# compute Gaussian RBF similarity measure
rbf_transformer = FunctionTransformer(rbf_kernel, kw_args=dict(Y=[[35.]],gamma=0.1))
age_simil_35 = rbf_transformer.transform(housing[[housing_median_age]])

# combine feature
ratio_transformer = FunctionTransformer(lambda X: X[:,[0]] / X[:,[1]])
retio_transformer.transform(np.array([[1.,2.],[3.,4.]]))


    `FunctionTransformer`는 매우 편리하지만, 트랜스포머가 학습 가능한 특성을 갖도록 하려면 `fit()` 메서드에서 일부 매개변수를 학습해야 한다. 이 경우 사용자 정의 클래스를 작성해야 한다.
    Scikit-Learn은 상속이 아닌 덕 타이핑(duck typing)을 기반으로 하므로 클래스를 생성고 `fit()`, `transform()`, `fit_transform()` 세 가지 메서드를 구현하면 된다.
   또한 `TransformerMixin`을 기본 클래스로 추가하면 `fit_transform()` 메서드를 무료로 얻을 수 있습니다. 또한 `BaseEstimator`를 기본 클래스로 추가하고 생성자에서 `*args`와 `**kwargs`를 피하면 자동 하이퍼파라미터 조정에 유용한 두 가지 추가 메서드(`get_params()`와 `set_params()`)도 제공된다.
    예를 들어, 자체적으로 `StandardScaler`를 구현할 수 있다.

from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.utils.validation import check_array, check_is,fitted

class StandardScalerClone(BaseEstimator, TransformerMixin):
	def __inin__(self, with_mean=True):
    	self.with_mean = with_mean
        
	def fit(self, X, y=None):
    	X = check_array(X)
        self.mean_ = X.mean(axis=0)
        self.scale_ = X.std(axis=0)
        self.n_features_in_ = X.shape[1]
        return self
        
    def transform(self, X):
    	check_is_fitted(self)
        X = check_array(X)
        assert self.n_features_in_ == X.shape[1]
        if self.with_mean:
        	X = X - self.mean_
        return X / self.scale_

변환 파이프라인

   Scikit-Learn은 변환의 연속적인 순서를 처리하기 위해 `Pipeline` 클래스를 제공한다. 지금까지 범주형 열과 수치 열을 별도로 처리했다. 각 열에 적절한 변환을 적용할 수 있는 단일 변환기가 있는 것이 편리하다. Scikit-Learn의 0.20 버전에서 이를 위해 `ColumnTransformer`가 도입되었다.

from sklearn.compose import ColumnTransformer

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

full_pipelin = ColumnTransformer([
	("num", num_pipeline, num_attribs),
    ("cat", OneHotEncoder(), cat_attribs)
])

housing_prepared = full_pipeline.fit_transform(housing)

학습 모델 선정 및 학습

훈련 및 평가

    모델 훈련과 평가 과정에서 선형 회귀 모델 및 의사결정 트리 회귀 모델을 사용하여 결과값을 예측한다. 이때 테스트 세트를 사용하기 전에 검증 세트를 활용하여 모델을 평가한다. 이를 통해 모델의 일반화 성능을 평가하고 과대적합 여부를 확인한다.

# 선형 모델
from sklearn.linear_model import LinearRegression

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

some_data = housing.iloc[:5]
some_labels = housing_labels.iloc[:5]
some_data_prepared = full_pipeline.transform(some_data)

print("Predictions", lin_reg.predict(some_data_prepared))
# Predictions: [286600.6045 317768.8069 210956.4333 59218.9888 189747.5584] 
print("Labels", list(some_labels))
# Labels: [ 286600.0, 340600.0, 196900.0, 46300.0, 254500.0]

# RMSE
from sklearn.metrics import mean_squared_error
housing_predictions = lin_reg.predict(housing_prepared)
lin_mse = mean_squared_error(housing_labels, housing_predictios)
lin_rmse = np.sqrt(lin_mse)
lin_rmse	# 68628.19819848922	 underfitting

# 의사 결정 모델
from sklearn.tree import DecisionTreeRegressor

tree_reg = DecisionTreeRegressor()
tree_reg.fit(housing_prepared, housing_labels)

housing_predictions = tree_reg.predict(housing_prepared)
tree_mse = mean_squaed_error(housing_labels, housing_predictions)
tree_rmse = np.sqrt(tree_mse)
tree_rmse	# 0.0 overfitting 가능성이 큼

교차 검증(Cross-Validation)을 사용한 더 나은 평가

    K-폴드 교차 검증(K-fold cross-validation)을 사용하여 모델의 성능을 평가하고 선형 회귀 모델과 RandomForestRegressor 모델을 비교한다. 이때, 모델이 훈련 세트에 과대적합되는지에 대한 주의사항을 강조한다. 이러한 과정을 통해 모델의 성능을 더 정확하게 평가하고 최적의 모델을 선택할 수 있다.

# k-fold cross validation
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)

def display_scores(scores):
	print("Scores:", scores)
    print("Mean:", scores.mean())
    print("Standard deviation:", scores.std())
    
display_scores(tree_rmse_scores)
# Scores: [70194,33680785 66855.163941 72432.58244769 70758.73896782 71115.88230639 75585.14172901 70262.86139133 70273.6325385 75366.87952553 71231.65726027]
# Mean: 71407.68766037929
# Standard devaiation: 2439.4345041191004	overfitting

# Linear Regression model
lin_scores = cross_val_score(lin_reg, housing_prepared, housing_labels, scoring = "neg_mean_squared_error", cv = 10)

lin_rmse_scores = np.sqrt(-lin_scores)
display_scores(lin_rmse_scores)
# Scores: [66782.73843989 66960.118071 70347.9524419 74739.57052552 68031.13388938 71193.84183426, 64969.63056405 68281.61137997]
# Mean: 69052.46136345083
# Standard devaiation: 2731.674001798348

# RandomForestRegressor
from sklearn.ensemble import RandomForestRegressor
forest_reg = RandomForestRegressor()
forset_reg.fit(housing_prepared, housing_labels)

forest_rmse	#18603.515021376355
display_scores(forest_rmse_score)
# Scores: [49519.80364233 47461.9115823 50029.02762854 52325.28068953 49308.10699751 53446.37892622 48634.8036574 47585.73832311 53490.10699751 50021.5852922]
# Mean: 50182.303100336096
# Standard devaiation: 2097.0810550985693

모델 조정

    Grid Search는 하이퍼파라미터 값의 조합을 수동으로 조절하는 대신 모든 가능한 조합을 시도하여 최적의 조합을 찾는 방법이다. Randomized Search는 하이퍼파라미터 공간에서 무작위로 조합을 선택하여 탐색하는 방법으로, 대규모 하이퍼파라미터 탐색에 적합하다. 이 두 방법을 사용하여 최적의 모델을 찾기 위해 여러 모델을 훈련하고 성능을 비교하는 방법이다.

from sklearn.model_selection import GridSearchCV

param_grid = [
	{'n_estimators': [3, 10, 30], 'max_features': [2, 4, 6, 8]},
    {'bootstrap': [False], 'n_estimators': [3, 10], 'max_features': [2,3,4]}
]

forest_reg = RandomForestRegressor()

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)

grid_search.best_params_	# {'max_features': 8, 'n_estimators': 30}
grid_search.best_estimator_

cvres = grid_search.cv_results_
for mean_score, params in zip(cvres["mean_test_score"], cvres["params"]):
	print(np.sqrt(-mean_score), params)


    그다음, 앙상블 방법(Ensemble Methods)은 여러 모델을 조합하여 최상의 예측 성능을 달성하는 방법으로, 모델 간 다양한 유형의 오류를 보완하는 데 도움이 된다.
    최적의 모델을 선택한 후, 모델의 상대적인 중요도와 모델의 성능을 테스트 세트에서 평가하는 방법으로 테스트 세트를 사용하여 모델의 최종 성능을 확인하고 일반화 오차에 대한 95% 신뢰 구간을 계산하는 방법이 있다.
    마지막으로, 모델을 테스트 세트에서 평가한 후에는 절대로 수정을 하지 말아야 한다. 만약 하이퍼파라미터를 수정한 순간부터 테스트 세트에 맞춰 학습되게 된다. 즉, 모델을 테스트 세트에 과적합되게 조정하면 새로운 데이터에 대한 일반화 능력이 떨어질 수 있으므로 조심해야 한다.

배포 및 관리(모니터링), 유지 보수

    모델 배포와 모니터링은 머신 러닝 프로젝트의 중요한 단계이다. 모델을 배포할 때는 훈련된 모델과 전처리 파이프라인을 저장하고, 이를 생산 환경에서 로드하여 예측에 활용한다. 클라우드 기반 플랫폼을 사용하여 모델을 배포하는 것도 효과적인 방법 중 하나이다.
    모니터링은 모델의 성능을 지속적으로 평가하고, 성능 하락 시 경보를 발생시키는 중요한 활동이다. 모델의 성능은 시간이 지남에 따라 저하될 수 있으므로 주기적인 모니터링이 필요하다. 또한 데이터의 변화에 대응하기 위해 데이터셋을 주기적으로 업데이트하고 데이터 품질을 확인하는 것이 중요하다. 마지막으로, 모델 백업 및 롤백 프로세스를 유지하여 모델의 장애 발생 시 빠르게 이전 모델로 복구할 수 있도록 대비하는 것이 좋다. 이러한 단계를 따르면 머신 러닝 모델을 효과적으로 운영 및 관리할 수 있다.


주섬주섬

  • 결측값이란 알려지지 않고, 수집되지 않거나 잘못 입력된 데이터 세트의 값을 의미한다.
  • 구글 코랩으로 연습을 해보는 것을 추천한다.

참고

   윗 코드들과 데이터의 출처이다.

 

GitHub - ageron/handson-ml2: A series of Jupyter notebooks that walk you through the fundamentals of Machine Learning and Deep L

A series of Jupyter notebooks that walk you through the fundamentals of Machine Learning and Deep Learning in Python using Scikit-Learn, Keras and TensorFlow 2. - GitHub - ageron/handson-ml2: A ser...

github.com

원하는 데이터 세트를 찾고 싶을 때 아래 사이트들을 추천한다.

 

Find Open Datasets and Machine Learning Projects | Kaggle

Download Open Datasets on 1000s of Projects + Share Projects on One Platform. Explore Popular Topics Like Government, Sports, Medicine, Fintech, Food, More. Flexible Data Ingestion.

www.kaggle.com

 

https://docs.aws.amazon.com/data-exchange/

 

docs.aws.amazon.com

 

UCI Machine Learning Repository

Welcome to the UC Irvine Machine Learning Repository We currently maintain 649 datasets as a service to the machine learning community. Here, you can donate and find datasets used by millions of people all around the world!

archive.ics.uci.edu

 

DataPortals.org - A Comprehensive List of Open Data Portals from Around the World

This service is run by Open Knowledge Foundation | Source Code | Download Data (CSV) | Download Data (JSON) | Data License (Public Domain) | Privacy Policy

dataportals.org

 

Nasdaq Data Link

The source for financial, economic, and alternative datasets, serving investment professionals.

data.nasdaq.com

 

AI-Hub

자세히보기 AI 허브가 추천하는 검색어입니다. 태그를 클릭하여 검색결과를 확인하세요.

aihub.or.kr

반응형

댓글