[핸즈온 머신러닝] 2. 머신러닝 프로젝트 처음부터 끝까지

박경민·2023년 3월 9일
0


주요 단계는 다음과 같다.

2.1 실제 데이터로 작업하기

2.2 큰 그림 보기

  • 캘리포니아 인구조사 데이터를 사용해 주택 가격 모델을 만들어야 함
  • 인구, 중간 소득, 중간 주택 가격 등을 담고 있음
  • 다른 측정 데이터가 주어졌을 때 중간 주택 가격을 예측해야 함.

2.2.1 문제 정의

비즈니스의 목적이 정확히 무엇인가요?

  • 아마 이 모델의 출력이 여러가지 다른 신호와 함께 다른 머신러닝 시스템에 입력으로 이용된다고 이야기할 수 있을 것이다.

파이프라인
데이터처리 컴포넌트들이 연속되어 있는 것을 파이프라인이라 하고, 이때 컴포넌트들은 비동기적으로 동작한다. (여기선 가볍게 독립적이라고 이해)

현재 솔루션은 어떻게 구성되어 있나요?

  • 현재는 구역 주택 가격을 전문가가 수동으로 추정한다고 알려줄 수 있다.
  • 따라서 사람이 하는 것보다 데이터를 기반으로 주택 가격을 예측하는 모델을 훈련시키는 쪽이 유용하다고 생각할 수 있다.

시스템의 설계를 어떻게 할까?

  • 지도 학습 (레이블된 훈련 샘플)
  • 다중 회귀 (feature 여러 개)
  • 단변량 회귀(구역마다 하나의 값을 예측한다면)
  • 다변량 회귀(구역마다 여러 값을 예측한다면)
  • 배치 학습 (적응이 필요없음)

2.2.2 성능 측정 지표 선택

평균 제곱근 오차를 성능 측정의 지표로 많이 사용한다.

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

만약 이상치로 보이는 구역이 많아보일 경우 평균 절대 오차를 사용할 수 있다.

2.2.3 가정 검사

지금까지 만든 가정을 나열하고 검사해보는 과정이다.

2.3.1 작업환경 만들기

2.3.2 데이터 다운로드

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()

데이터를 읽어들이는 간단한 함수. 이 함수는 판다스의 데이터프레임 객체를 반환한다.

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 데이터 구조 훑어보기

housing = load_housing_data()
housing.head()

특성은 총 10개로 확인되었는데, info()를 찍어보자.

샘플의 수는 20640 이며, total_rooms 만 그 수를 지키지 않고 있다.

ocean_proximity 제외 모두 숫자형이다. 아마 이 특성은 범주형 자료일 것인데, value_counts() 를 찍어보자.

describe() 를 사용하면 숫자형 특성의 요약 정보를 확인할 수 있다.

std 는 표준편차, %가 붙은 값은 백분위수 (백분율이 속하는 하위 부분의 값) 이다.

숫자형 특성을 히스토그램으로 그려보는 것 또한 중요하다. hist() 메서드를 통해 모든 숫자형 특성에 대한 히스토그램을 출력한다.

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

  • median income 은 스케일 조정이 수행되었다.
  • housing median age, median house value 역시 최대, 최소값이 한정되었다.
  • 특성들의 스케일이 서로 많이 다르다.
  • 히스토그램의 꼬리가 두껍다.

2.3.4 테스트 세트 만들기

테스트 세트로만 일반화 오청을 추정하여 낙관적인 추정이 이루어지며, 론칭 시 기대한 성능이 나오지 않는 것을 데이터 스누핑 편향이라고 한다.

테스트 세트를 생성하는 코드는 다음과 같다. (보통 7:3, 8:2 정도로 나눈다.)

import numpy as np

# 예시로 만든 것입니다. 실전에서는 사이킷런의 train_test_split()를 사용하세요.
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 = shuffled_indices[test_set_size:]
    return data.iloc[train_indices], data.iloc[test_indices]
    
train_set, test_set = split_train_test(housing, 0.2)
len(train_set)

당연히 실전에서는 이를 함수가 아닌 train_test_split() 을 사용하긴 한다.

  • 위 코드는 프로그램을 다시 실행할 대마다 다른 테스트 세트가 생성된다.
  • 이러한 문제를 방지하기 위해 해시값을 계산하거나 행의 인덱스를 ID로 사용하는 함수를 만들어 볼 수 있으나, 여기서 코드를 기재하진 않겠다.

사이킷런은 데이터셋을 여러 서브셋으로 나누는 다양한 방법을 제공한다.(train_test_split() 메서드)

from sklearn.model_selection import train_test_split

train_set, test_set = train_test_split(housing, test_size=0.2, random_state=42)
  • 난수 초깃값을 지정할 수 있는 random_state 매개변수가 있다.
  • 행의 개수가 같은 여러개의 데이터셋을 인덱스를 기반으로 나눌 수 있다. (데이터프레임이 레이블에 따라 여러 개로 나뉘어 있을 경우)

이는 모두 순수한 무작위 샘플링 방식에 속하고, 다른 하나로 계층적 샘플링이 있다. 계층적 샘플링은 전체 인구를 계층이라는 동질의 그룹으로 나누고, 테스트 세트가 전체 인구를 대표하도록 각 계층에서 올바른 수의 샘플을 추출하는 것이다.

또한 테스트 세트가 여러 소득 카테고리를 잘 대표하도록 만들어야 한다.

이를 위해 median_income 에 대하여 카테고리를 만들어줄 수 있다.
bins 를 통해 범위를, labels 를 통해 해당 범위에 라벨을 담아줄 수 있다.

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()

이제 소득 카테고리를 기반으로 계층 샘플링을 해보자.

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)S

테스트 세트에서 소득 카테고리의 비율이다.

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

2.4.1 지리적 데이터 시각화

위도와 경도가 있으니 모든 구역을 산점도로 만들어 데이터를 시각화하자.

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

alpha 옵션을 0.1 로 주변 데이터 포인트가 밀집된 영역을 잘 보여준다.
(눈을 흐릿하게 뜨고 보는 느낌?)

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

주택 가격을 여기에 나타내보자. 구역의 인구를 나타내는 s 와 가격을 나타내는 c를 추가하자. 컬러 맵에서 파란색-빨간색까지 범위를 가지는 jet 도 사용해보자.

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)

이 그림에서 주택 가격이 지역(바다와 가까운 지역)과 인구 밀도에 관련성이 깊은 것을 확인할 수 있다.

2.4.2 상관관계 조사

데이터셋이 너무 크지 않을 땐 직접적으로 표준 상관계수 corr() 를 찍어볼 수도 있다.

위 그림은 상관계수 -1~1에 따른 점들의 모양이다. (피어슨 상관계수)

또 다른 방법으로 숫자형 특성 사이에 산점도를 그려주는 scatter_matrix() 를 이용하는 것이다.


from pandas.plotting import scatter_matrix

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


각 숫자형 피처간의 산점도를 확인할 수 있다. 이 중에서도 median_income 과 median_house_value 가 눈에 걸린다.

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

  • 매우 강한 상관관계라 할 수 있다.
  • 가격 제한 값이 500000으로 잘 보인다.
  • 직선에 가까운 형태가 더 있는데 이에 대한 제거가 필요하다.

2.4.3 특성 조합으로 실험

새로운 피처들을 가공하는 것이다.

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["median_house_value"].sort_values(ascending=False)

bedrooms_per_room 은 꽤 좋은 피처라 할 수 있다.

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

profile
Mathematics, Algorithm, and IDEA for AI research🦖

0개의 댓글