LLM 엔지니어링1장 · 머신러닝 프로세스와 기본 개념8 / 23← 이전목차다음 →MetaContents

1장. 머신러닝 프로세스와 기본 개념

학습용과 시험용 나누기

시험 공부를 떠올려 보세요. 문제집으로 공부하고, 모의고사로 실력을 점검하고, 본시험으로 성적을 받습니다. 본시험 문제를 미리 봤다면 점수가 높아도 실력이라고 할 수 없습니다. 머신러닝도 데이터를 쓰임에 따라 묶음으로 나눕니다.

전체 데이터를 학습용, 검증용, 시험용 세 묶음으로 나누는 모습을 문제집, 모의고사, 본시험에 견준 그림

왼쪽부터 학습용이 문제집, 검증용이 모의고사, 시험용이 본시험입니다. 학습용으로 배우고, 검증용으로 설정을 고르고, 시험용으로 마지막에 한 번 성적을 매깁니다.

세 묶음

묶음쓰임시험 공부로 치면보통의 비율
학습용모델이 보고 배운다문제집60~80%
검증용모델의 설정(나무의 깊이 등)을 고른다모의고사10~20%
시험용마지막에 한 번 성적을 매긴다본시험10~20%

데이터가 적을 때는 검증용을 따로 떼지 않고 학습용 안에서 돌아가며 검증하기도 합니다(교차 검증). 이 장에서는 학습용과 시험용 두 묶음만 씁니다.

train_test_split

scikit-learn 의 train_test_split 이 섞어서 나눠 줍니다. 지연처럼 한쪽이 적은 정답이면 stratify 를 꼭 줍니다. 학습용과 시험용의 지연 비율이 되도록 똑같아지게 나눠 줍니다.

Python
import pandas as pd
from sklearn.model_selection import train_test_split

# 배송 주문 10건(설명용으로 지어낸 표): 지연은 3건
orders = pd.DataFrame({
    "주문번호": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110],
    "거리km":   [5, 180, 12, 150, 8, 90, 200, 20, 15, 60],
    "주문시각": [10, 21, 9, 22, 14, 18, 23, 11, 13, 16],
    "지연":     [0, 1, 0, 1, 0, 0, 1, 0, 0, 0],
})
X = orders[["거리km", "주문시각"]]   # 특성
y = orders["지연"]                   # 레이블

# test_size=0.3  : 30% 를 시험용으로 뗀다(10건 가운데 3건)
# random_state=42: 섞는 순서를 고정해서 다시 실행해도 같게 나눈다
# stratify=y     : 지연 비율을 학습용과 시험용에 되도록 똑같이 나눈다
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42, stratify=y
)
# 결과: 각 묶음에 들어간 주문번호와 두 묶음의 지연 비율
print("학습용 주문:", orders.loc[X_train.index, "주문번호"].tolist())
print("시험용 주문:", orders.loc[X_test.index, "주문번호"].tolist())
print("지연 비율 학습용", round(y_train.mean(), 2), "· 시험용", round(y_test.mean(), 2))

10건 가운데 7건(104, 101, 105, 108, 109, 103, 107번)이 학습용, 3건(102, 110, 106번)이 시험용으로 나뉩니다. 지연 비율은 학습용 0.29(7건 가운데 2건), 시험용 0.33(3건 가운데 1건)입니다. 건수가 적으면 비율을 딱 맞출 수 없어서, stratify 는 할 수 있는 만큼 가장 가깝게 나눕니다. 실습 4의 배송 데이터 1,194건에서는 학습용 0.206, 시험용 0.207 로 거의 같아집니다. 돌려받는 순서가 X_train, X_test, y_train, y_test 라는 점을 눈여겨보세요. 순서를 바꿔 받으면 엉뚱한 묶음으로 학습하게 됩니다.

코드에 나오는 함수

코드쉬운 뜻
from sklearn.model_selection import train_test_splitmodel selection(모델 고르기) 묶음에서 불러온다. train(학습)과 test(시험)로 split(나누기)한다는 이름이다
test_size=0.3전체의 30% 를 시험용으로 뗀다
random_state=42섞는 순서의 씨앗이다. 같은 숫자를 주면 몇 번을 돌려도 똑같이 나뉜다
stratify=ystratify 는 "층을 나누다"라는 뜻이다. y 의 값(지연, 정시)마다 따로 나눠서 두 묶음의 지연 비율을 맞춘다
X_train, X_test, y_train, y_test = ...네 묶음을 이 순서로 돌려받는다. 학습용 특성, 시험용 특성, 학습용 정답, 시험용 정답이다
X_train.index학습용에 들어간 행의 번호표다. 섞여도 원래 표의 번호를 그대로 들고 다닌다
orders.loc[번호들, "주문번호"]loc 는 location(위치)의 줄임말이다. 행 번호표와 열 이름으로 값을 꺼낸다
y_train.mean()0 과 1 의 평균은 1 의 비율이다. 곧 지연 비율이다

이 코드가 뜻하는 것

문제 카드 열 장을 잘 섞어 일곱 장은 문제집으로, 세 장은 본시험으로 봉투에 넣는 일입니다. 어려운 카드(지연)가 한 봉투에 몰리지 않게, 어려운 카드끼리 따로 섞어서 나눠 담습니다. 여기서 카드가 주문 한 건, 어려운 카드끼리 따로 나누는 것이 stratify=y 입니다.

줄하는 일쉽게 말하면
orders = pd.DataFrame({...})주문 10건을 만든다. 지연이 3건이다카드 열 장, 어려운 카드 세 장
X = ..., y = ...특성과 정답을 나눈다카드 앞면(문제)과 뒷면(답)
train_test_split(...)섞어서 7건과 3건으로 나눈다문제집 봉투와 본시험 봉투에 나눠 담는다
orders.loc[X_train.index, "주문번호"]각 묶음에 든 주문번호를 본다봉투 안의 카드 번호를 확인한다
round(y_train.mean(), 2)묶음마다 지연 비율을 본다봉투마다 어려운 카드가 얼마나 들었나

학습용 0.29 와 시험용 0.33 은 어려운 카드가 두 봉투에 2장, 1장으로 고르게 갔다는 뜻입니다. 세 장을 7장과 3장 봉투에 나누면 이보다 더 가깝게 맞출 수는 없습니다.

작게 줄여서 눈으로 보기

stratify 를 빼면 어떻게 되는지 봅니다. 같은 10건(지연 3건)을 섞는 씨앗만 바꿔 가며 나누고, 시험용 3건에 지연이 몇 건 들었는지 셉니다. 특성은 설명을 위해 0 부터 9 까지의 번호로 대신했습니다.

Python
from sklearn.model_selection import train_test_split

y = [0, 1, 0, 1, 0, 0, 1, 0, 0, 0]   # 지연 3건, 정시 7건
X = [[i] for i in range(10)]

# stratify 없이 섞는 순서(random_state)만 바꿔 가며 시험용의 지연 수를 센다
for seed in range(5):
    _, _, _, y_test = train_test_split(X, y, test_size=0.3, random_state=seed)
    print("random_state", seed, "→ 시험용 지연", sum(y_test), "건")

# stratify=y 를 주면
_, _, _, y_test = train_test_split(X, y, test_size=0.3, random_state=0, stratify=y)
print("stratify 사용 → 시험용 지연", sum(y_test), "건")
출력
random_state 0 → 시험용 지연 0 건
random_state 1 → 시험용 지연 1 건
random_state 2 → 시험용 지연 1 건
random_state 3 → 시험용 지연 1 건
random_state 4 → 시험용 지연 1 건
stratify 사용 → 시험용 지연 1 건
결과읽는 법
random_state 0 → 시험용 지연 0 건운이 나쁘면 시험용에 지연이 하나도 없다. 이러면 "지연을 몇 건 찾았나"를 잴 수가 없다
random_state 1 ~ 4 의 1 건대개는 한 건이 들어가지만, 씨앗에 따라 달라진다
stratify 사용 → 시험용 지연 1 건같은 씨앗 0 이어도 지연을 나눠 담아 시험용에 한 건이 들어간다

_ 는 받기는 하지만 쓰지 않을 값을 담는 이름입니다. 네 묶음 가운데 y_test 만 필요해서 나머지 셋을 _ 로 받았습니다.

주의할 점

  • 시험용 데이터는 마지막에 한 번만 봅니다. 시험 점수를 보며 설정을 여러 번 고치면, 시험 문제를 미리 본 것과 같아집니다. 그때는 검증용을 따로 둡니다.
  • 정제할 때 쓰는 값(예: 빈칸을 채울 중앙값)도 원래는 학습용에서만 구합니다. 이 장의 실습 2는 흐름을 보이려고 나누기 전에 정제했습니다. 2장부터는 나눈 뒤에 구합니다.
  • stratify 를 빼면 운에 따라 시험용에 지연이 거의 없을 수도 있습니다. 그러면 재현율 같은 지표가 크게 흔들립니다.
← 이전 절1장 · scikit-learn 의 네 동작다음 절 →1장 · 과적합