데이터 셋이 충분히 크다면 일반 훈련 데이터 셋을 무작위로 샘플링 하여도 큰 문제가 발생하지 않는다. 하지만 그렇지 않으면 데이터 편향이 생길 가능성이 크다. 예를들어 여론 설문조사 기관에서 무작위로 1,000명을 선정해 조사를 한다고 가정하자. 무작위로 선정한 1,000명이, 물론 그럴 가능성은 거의 없겠지만 한 성별로만 이루어져 있거나 특정 연령대에 집중되어 있는 경우, 그 데이터 셋에 충분히 신뢰가 가진 않을 것이다. 이를 위해 전체 인구를 계층이라는 동질의 그룹으로 나누고, 테스트 세트가 전체 인구를 대표하도록 각 계층에서 올바른 수의 샘플을 추출한다. 인구 계층을 성별에 따라 남성와 여성으로 나눈다고 가정하자. 2020년 우리나라 남녀 성비는 남자가 50.1%, 여자가 49.9%이다. 여기서 전체 인구를 대표할 수 있는 1,000명을 선택하기 위해 노력한다면 샘플에서도 이 성비를 유지해 남성을 501명 여성을 499명을 뽑는 것이 합리적이다.

Scikit-learn모듈에서는 계층 샘플링을 위한 API를 제공한다.

 

Python Scikit-learn sklearn.model_selection API

API Reference — scikit-learn 0.23.1 documentation scikit-learn.org Scikit-learn API - sklearn.model_selection 훈련세트와 테스트 세트를 나눌 때, 교차검증을 위한 검증 세트를 나눌 때, 하이퍼 파라미터..

dsbook.tistory.com

 

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

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
반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 라이프코리아트위터 공유하기
  • shared
  • 카카오스토리 공유하기