주요 단계는 다음과 같다.
비즈니스의 목적이 정확히 무엇인가요?
파이프라인
데이터처리 컴포넌트들이 연속되어 있는 것을 파이프라인이라 하고, 이때 컴포넌트들은 비동기적으로 동작한다. (여기선 가볍게 독립적이라고 이해)
현재 솔루션은 어떻게 구성되어 있나요?
시스템의 설계를 어떻게 할까?
평균 제곱근 오차를 성능 측정의 지표로 많이 사용한다.
RMSE(X, h)는 가설 h를 사용하여 일련의 샘플을 평가하는 비용함수이다.
만약 이상치로 보이는 구역이 많아보일 경우 평균 절대 오차를 사용할 수 있다.
지금까지 만든 가정을 나열하고 검사해보는 과정이다.
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)
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()
테스트 세트로만 일반화 오청을 추정하여 낙관적인 추정이 이루어지며, 론칭 시 기대한 성능이 나오지 않는 것을 데이터 스누핑 편향이라고 한다.
테스트 세트를 생성하는 코드는 다음과 같다. (보통 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() 을 사용하긴 한다.
사이킷런은 데이터셋을 여러 서브셋으로 나누는 다양한 방법을 제공한다.(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)
이는 모두 순수한 무작위 샘플링 방식에 속하고, 다른 하나로 계층적 샘플링이 있다. 계층적 샘플링은 전체 인구를 계층이라는 동질의 그룹으로 나누고, 테스트 세트가 전체 인구를 대표하도록 각 계층에서 올바른 수의 샘플을 추출하는 것이다.
또한 테스트 세트가 여러 소득 카테고리를 잘 대표하도록 만들어야 한다.
이를 위해 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
테스트 세트에서 소득 카테고리의 비율이다.
위도와 경도가 있으니 모든 구역을 산점도로 만들어 데이터를 시각화하자.
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)
이 그림에서 주택 가격이 지역(바다와 가까운 지역)과 인구 밀도에 관련성이 깊은 것을 확인할 수 있다.
데이터셋이 너무 크지 않을 땐 직접적으로 표준 상관계수 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)
새로운 피처들을 가공하는 것이다.
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 은 꽤 좋은 피처라 할 수 있다.