문자열을 숫자로 바꾸기 전에 물어볼 질문
범주형 변수는 도시·등급·상품군처럼 값이 그룹을 뜻하는 변수다. 모델은 보통 숫자를 입력으로 받지만, 아무 숫자나 붙이면 모델이 그 숫자의 크기와 간격까지 의미로 받아들일 수 있다.
첫 질문은 “범주 사이에 실제 순서가 있는가?”다. 순서가 있으면 Ordinal, 순서가 없으면 대개 OneHot을 출발점으로 삼는다.
Ordinal과 OneHot의 차이
Ordinal encoding: 낮음 < 보통 < 높음처럼 업무적으로 합의된 순서를 한 열의 정수로 표현한다. 단, 0→1과 1→2의 간격이 같다는 뜻까지 자동으로 생기므로 모델과 해석에 주의한다.
One-hot encoding: 서울·부산·대구처럼 순서 없는 각 범주를 별도 0/1 열로 만든다. 숫자 크기에 따른 거짓 순서를 피하지만 범주가 많으면 열과 메모리가 늘어난다.
LabelEncoder는 목표값 y의 라벨을 인코딩하는 도구다. 입력 특성 X의 여러 범주형 열에는 OrdinalEncoder나 OneHotEncoder를 사용한다.
실습: 미지 범주까지 안전하게 변환하기
아래 예제는 학습 데이터에만 인코더를 맞춘 뒤 새 데이터의 부산을 처리한다. handle_unknown="ignore"이면 미지 범주의 one-hot 행은 모두 0이 된다.
import numpy as np
from sklearn.preprocessing import OneHotEncoder, OrdinalEncoder
train_city = np.array([["서울"], ["대구"], ["서울"]])
test_city = np.array([["부산"], ["대구"]])
onehot = OneHotEncoder(handle_unknown="ignore", sparse_output=False)
onehot.fit(train_city)
print(onehot.categories_[0].tolist())
print(onehot.transform(test_city).astype(int).tolist())
level = np.array([["낮음"], ["높음"], ["보통"]])
ordinal = OrdinalEncoder(
categories=[["낮음", "보통", "높음"]],
handle_unknown="use_encoded_value",
unknown_value=-1,
)
ordinal.fit(level)
print(ordinal.transform([["매우 높음"], ["보통"]]).astype(int).ravel().tolist())
['대구', '서울']
[[0, 0], [1, 0]]
[-1, 1]
모두 0 또는 -1은 “범주가 없다”가 아니라 “학습 때 보지 못했다”는 약속이다. 운영 로그에서 미지 범주 비율을 따로 감시해야 데이터 변화가 조용히 숨지 않는다.
희소 범주와 고카디널리티
범주 수가 많은 우편번호·상품 ID를 그대로 one-hot하면 열이 폭증하고, 아주 드문 범주는 우연한 패턴을 학습하기 쉽다. scikit-learn의 min_frequency 또는 max_categories는 학습 데이터에서 드문 범주를 하나의 infrequent 그룹으로 묶는다. 기본 출력은 희소 행렬이므로 대규모 데이터에서 함부로 dense 배열로 바꾸지 않는다.
의미가 같은 철자·공백·대소문자를 먼저 정규화한다.
업무상 같은 상위 그룹이 있으면 상품→상품군처럼 도메인 매핑한다.
빈도 임계값은 전체 데이터가 아니라 학습 폴드에서 결정한다.
식별자에 가까운 고유값은 삭제·해싱·집계 특성 등 다른 표현을 검토한다.
더미 변수 함정은 언제 문제인가
절편이 있는 비정규화 선형모델에서는 모든 one-hot 열의 합이 1이어서 완전한 다중공선성이 생길 수 있다. 한 열을 기준 범주로 빼는 drop="first"가 이를 피하지만, 범주 표현의 대칭을 깨뜨려 규제가 있는 모델에서 편향을 만들 수도 있다. 트리 모델이나 규제가 있는 예측 문제에서 기계적으로 한 열을 버릴 필요는 없다.
누수 없는 프로젝트 적용 순서
먼저 train/test를 나눈다. 분할 기준은 시간·사용자·그룹 구조까지 반영한다.
인코더의 범주, 희소 범주 임계값, 타깃 기반 통계는 train에서만 학습한다.
ColumnTransformer와 Pipeline에 전처리를 넣어 각 교차검증 학습 폴드에서만 fit되게 한다.
검증·테스트·운영 데이터에는 transform만 적용하고 미지 범주율을 기록한다.
특히 target encoding은 범주별 목표값 평균을 사용하므로 같은 행의 정답이 인코딩에 섞이지 않도록 교차 적합(cross-fitting)이 필요하다. 단순 one-hot보다 누수 위험이 크다.
핵심 체크리스트
범주의 순서가 실제 업무 의미인지 확인했다.
unknown과 missing의 표현을 구분했다.
희소 범주 규칙을 학습 데이터에서만 정했다.
인코더와 모델을 하나의 Pipeline으로 묶었다.
참고 자료
scikit-learn OneHotEncoder 공식 문서 — 미지·희소 범주, sparse_output과 drop 동작 (2026-08-05 확인)
scikit-learn OrdinalEncoder 공식 문서 — unknown_value와 범주 순서 지정 (2026-08-05 확인)
scikit-learn 데이터 누수 가이드 — 분할 전 전처리 금지와 Pipeline 원칙 (2026-08-05 확인)
실전 Feature Engineering 강의 PDF 47~51쪽 — label·one-hot·dummy coding과 대규모 범주 문제 (2026-08-05 확인)
댓글 0
댓글을 불러오는 중…