데이터 셋이 충분히 크다면 일반 훈련 데이터 셋을 무작위로 샘플링 하여도 큰 문제가 발생하지 않는다. 하지만 그렇지 않으면 데이터 편향이 생길 가능성이 크다. 예를들어 여론 설문조사 기관에서 무작위로 1,000명을 선정해 조사를 한다고 가정하자. 무작위로 선정한 1,000명이, 물론 그럴 가능성은 거의 없겠지만 한 성별로만 이루어져 있거나 특정 연령대에 집중되어 있는 경우, 그 데이터 셋에 충분히 신뢰가 가진 않을 것이다. 이를 위해 전체 인구를 계층이라는 동질의 그룹으로 나누고, 테스트 세트가 전체 인구를 대표하도록 각 계층에서 올바른 수의 샘플을 추출한다. 인구 계층을 성별에 따라 남성와 여성으로 나눈다고 가정하자. 2020년 우리나라 남녀 성비는 남자가 50.1%, 여자가 49.9%이다. 여기서 전체 인구를 대표할 수 있는 1,000명을 선택하기 위해 노력한다면 샘플에서도 이 성비를 유지해 남성을 501명 여성을 499명을 뽑는 것이 합리적이다.
Scikit-learn모듈에서는 계층 샘플링을 위한 API를 제공한다.
1. 데이터 셋 준비
# 데이터 셋 다운받기 -> 현재작업중인폴더/datasets/housing/housing.tgz
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):
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)
# housing 데이터 형태는 dataframe
housing = load_housing_data()
housing.head()
2. housing["median_income"] 카테고리 범주화
# "median_income" 카테고리 범주화
# [0. ~ 1.5) : 1
# [1.5 ~ 3.0) : 2
# [3.0 ~ 4.5) : 3
# [4.5 ~ 6.0) : 4
# [6.0 ~ ) : 5
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"].value_counts()
housing["income_cat"].hist()
3. StratifiedShuffleSplit를 사용한 계층적 샘플링
from sklearn.model_selection import StratifiedShuffleSplit
# split는 StratifiedShuffleSplit의 객체
split = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)
# StratifiedShuffleSplit의 메소드 split로 train, test를 분할할 index 생성
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]
from sklearn.model_selection import train_test_split
# 무작위 샘플링
train_set, test_set = train_test_split(housing, test_size=0.2, random_state=42)
def income_cat_proportions(data):
return data["income_cat"].value_counts() / len(data)
compare_props = pd.DataFrame({
"Overall": income_cat_proportions(housing),
"Stratified_train": income_cat_proportions(strat_train_set),
"Stratified_test" : income_cat_proportions(strat_test_set),
"Random_train" : income_cat_proportions(train_set),
"Random_test": income_cat_proportions(test_set),
}).sort_index()
compare_props["Strat_test. %error"] = 100 * compare_props["Stratified_test"] / compare_props["Overall"] - 100
compare_props["Rand_test. %error"] = 100 * compare_props["Random_test"] / compare_props["Overall"] - 100
728x90
반응형
최근댓글