Programming

[5편] 머신러닝 데이터 전처리 기본기: 인코딩·스케일링 실습 정리개요

Lucas.Kim 2025. 12. 10. 15:34
반응형

앞선 1~4편에서 사이킷런을 활용해 모델 학습, 교차검증, 하이퍼파라미터 튜닝까지 기본 흐름을 살펴보았습니다.
하지만 좋은 모델을 만들기 위해서는 알고리즘 선택만큼 중요한 단계가 있습니다. 바로 **데이터 전처리(Data Preprocessing)**입니다.

이번 5편에서는 데이터 전처리 전반의 개념을 간단히 정리한 뒤, 그 중에서 특히 자주 사용되는 두 가지를 실습합니다.

  • 문자열 데이터를 숫자로 바꾸는 데이터 인코딩 (Label Encoding, One-Hot Encoding)
  • 피처의 스케일(크기)를 맞추는 데이터 스케일링 (StandardScaler, MinMaxScaler)

모든 예제는 사이킷런과 간단한 리스트/데이터프레임을 이용하며, 코드에는 줄 단위로 자세한 주석을 추가했습니다.

1. 데이터 전처리 전체 흐름 살펴보기

실무에서 데이터 전처리는 보통 다음과 같은 단계들을 포함합니다.

  1. 데이터 클린징(Data Cleansing)
    • 이상한 값, 잘못된 형식, 중복 데이터 등을 정리합니다.
  2. 결손값 처리(Missing Value Handling)
    • NaN, NULL 같은 결측값을 삭제하거나 평균/중앙값/최빈값 등으로 대체합니다.
  3. 데이터 인코딩(Data Encoding)
    • 문자열(범주형) 데이터를 모델이 학습할 수 있는 숫자형 데이터로 변환합니다.
    • 예: “TV”, “냉장고” → 0, 1 또는 원-핫 인코딩 벡터
  4. 데이터 스케일링(Data Scaling)
    • 피처마다 값의 범위가 크게 다를 경우, 스케일을 맞춰줍니다.
    • 정규화(Normalization), 표준화(Standardization) 등의 방식 사용
  5. 이상치 제거(Outlier Handling)
    • 극단값을 탐지하고 제거하거나 적절히 조정합니다.
  6. Feature 선택 / 추출 / 가공 (Feature Engineering)
    • 불필요한 피처 제거, 중요한 피처 선택, 새로운 파생 변수 생성 등

이번 글에서는 이 중에서 3. 인코딩4. 스케일링을 중심으로 구체적인 코드와 함께 살펴보겠습니다.

2. 데이터 인코딩 – 문자열을 숫자로 바꾸기

머신러닝 알고리즘은 문자열 데이터를 직접 입력으로 받지 못합니다.
따라서 범주형 변수(상품명, 도시, 등급 등)는 반드시 숫자형으로 변환해야 합니다.

대표적인 인코딩 방식은 다음 두 가지입니다.

  • 레이블 인코딩(Label Encoding)
  • 원-핫 인코딩(One-Hot Encoding)

2-1. 레이블 인코딩(Label Encoding)

레이블 인코딩은 각 범주를 정수값 하나에 매핑하는 방식입니다.

예:

  • “TV” → 0
  • “냉장고” → 1
  • “컴퓨터” → 2

사이킷런의 LabelEncoder 클래스를 사용합니다.

# -----------------------------------------------------------
# 레이블 인코딩(Label Encoding) 예제
# -----------------------------------------------------------

# 문자열 범주형 데이터를 정수 레이블로 변환하기 위한 인코더
from sklearn.preprocessing import LabelEncoder

# 1. 인코딩할 원본 데이터 정의
# - 가전제품 이름이 문자열 형태로 되어 있는 리스트
items = ['TV', '냉장고', '컴퓨터', '선풍기', 'TV', '컴퓨터', '믹서', '믹서', '냉장고']
print("원본 데이터:", items)

# 2. LabelEncoder 객체 생성
encoder = LabelEncoder()

# 3. fit()으로 고유 범주 학습
# - items 안에 어떤 카테고리들이 있는지 내부적으로 기억합니다.
encoder.fit(items)

# 4. transform()으로 실제 정수 인코딩 수행
# - 각 문자열을 정수 형태로 변환합니다.
labels = encoder.transform(items)
print("레이블 인코딩 결과:", labels)

# 5. 인코딩 기준 확인
# - encoder.classes_에는 학습된 고유 카테고리가 정렬된 상태로 저장됩니다.
print("인코딩 클래스 목록:", encoder.classes_)

# 6. inverse_transform()으로 다시 문자열로 복원 가능
# - 정수 레이블을 다시 원래 문자열 카테고리로 되돌립니다.
original_items = encoder.inverse_transform(labels)
print("역변환 결과:", original_items)

레이블 인코딩은 간단하지만, 숫자의 크기에 의미가 생긴다는 문제가 있습니다.
예를 들어 “TV(0) < 냉장고(1) < 컴퓨터(2)”처럼 순서가 있는 값처럼 오해할 수 있기 때문에, 순서가 없는 범주형 변수에는 주의해서 사용해야 합니다. 이럴 때는 보통 원-핫 인코딩을 더 선호합니다.


2-2. 원-핫 인코딩(One-Hot Encoding)

원-핫 인코딩은 각 범주마다 새로운 컬럼을 만들어 해당 범주에만 1, 나머지는 0을 주는 방식입니다.

예: “TV”, “냉장고”, “컴퓨터” → 3개의 컬럼 생성

  • TV → [1, 0, 0]
  • 냉장고 → [0, 1, 0]
  • 컴퓨터 → [0, 0, 1]

(1) OneHotEncoder + NumPy 사용

# -----------------------------------------------------------
# 원-핫 인코딩(One-Hot Encoding) 예제 - OneHotEncoder + NumPy
# -----------------------------------------------------------

from sklearn.preprocessing import OneHotEncoder
import numpy as np

# 1. 원-핫 인코딩할 원본 데이터
#   주의: OneHotEncoder는 2차원 배열 입력을 요구하므로
#   우선 리스트를 2차원 형태로 변환합니다.
items = ['TV', '냉장고', '컴퓨터', '선풍기', 'TV', '컴퓨터', '믹서', '믹서', '냉장고']

# 2. NumPy 배열로 변환 후 reshape(-1, 1)로 2차원 형태 만들기
#   - (-1, 1)의 의미: 행 개수는 자동 결정, 열은 1개
items_array = np.array(items).reshape(-1, 1)
print("2차원 형태의 입력 데이터:\n", items_array)

# 3. OneHotEncoder 객체 생성
oh_encoder = OneHotEncoder()

# 4. fit()으로 고유 범주 학습
oh_encoder.fit(items_array)

# 5. transform()으로 원-핫 인코딩 수행
#   - 반환값은 희소행렬(sparse matrix)이므로 메모리를 효율적으로 사용합니다.
oh_labels = oh_encoder.transform(items_array)
print("원-핫 인코딩 결과(희소 행렬):\n", oh_labels)

# 6. toarray()로 밀집(dense) 배열 형태로 변환
oh_dense = oh_labels.toarray()
print("원-핫 인코딩 결과(배열):\n", oh_dense)

# 7. 결과의 형태(shape) 확인
print("원-핫 인코딩 배열 shape:", oh_dense.shape)

(2) Pandas get_dummies() 사용

실무에서는 OneHotEncoder보다 pd.get_dummies()를 더 자주 사용하는 경우도 많습니다.
DataFrame 기반 작업에 특히 편리합니다.

# -----------------------------------------------------------
# 원-핫 인코딩(One-Hot Encoding) 예제 - pandas.get_dummies()
# -----------------------------------------------------------

import pandas as pd

# 1. 원본 데이터를 DataFrame으로 생성
df = pd.DataFrame({'items': ['TV', '냉장고', '컴퓨터', '선풍기',
                             'TV', '컴퓨터', '믹서', '믹서', '냉장고']})

print("원본 DataFrame:\n", df)

# 2. get_dummies()를 이용해 원-핫 인코딩 수행
#   - dtype=int로 설정하면 True/False가 아니라 0/1 정수형으로 반환
df_oh = pd.get_dummies(df, dtype=int)

print("원-핫 인코딩된 DataFrame:\n", df_oh)

get_dummies()는 내부적으로 컬럼명을 자동으로 정리해 주기 때문에, 간단한 범주형 인코딩에는 아주 효율적입니다.


3. 데이터 스케일링 – 피처 크기를 맞춰주기

3-1. 피처 스케일링의 필요성

각 피처마다 값의 범위가 크게 다르면, 일부 알고리즘은 특정 피처에 과도하게 영향을 받을 수 있습니다.

  • 예:
    • 피처 A: 0.1 ~ 1.0
    • 피처 B: 1,000 ~ 100,000

이 경우 거리 기반/선형 계열 알고리즘은 값의 크기가 큰 피처에 더 민감하게 반응합니다.

대표적인 스케일링 방식:

  1. 표준화(Standardization)
    • 평균 0, 분산 1인 정규분포 형태로 변환
    • StandardScaler 사용
  2. 정규화(Normalization, Min-Max Scaling)
    • 최소값 0, 최대값 1 범위로 변환
    • MinMaxScaler 사용

특히 선형 모델(Linear Regression, Logistic Regression), SVM, KNN, 신경망 등은 스케일링에 매우 민감합니다.


3-2. StandardScaler – 평균 0, 분산 1로 표준화

# -----------------------------------------------------------
# StandardScaler 예제: 평균 0, 분산 1로 스케일링
# -----------------------------------------------------------

from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_iris
import pandas as pd

# 1. 아이리스 데이터 로딩
iris = load_iris()
iris_data = iris.data

# 2. DataFrame으로 변환 (컬럼명 포함)
iris_df = pd.DataFrame(data=iris_data,
                       columns=iris.feature_names)

# 3. 스케일링 전 각 피처의 평균과 분산 출력
print("스케일링 전 feature 평균값:\n", iris_df.mean())
print("스케일링 전 feature 분산값:\n", iris_df.var())

# 4. StandardScaler 객체 생성
scaler = StandardScaler()

# 5. fit()으로 각 피처의 평균과 표준편차 학습
scaler.fit(iris_df)

# 6. transform()으로 실제 스케일링 적용
#   - 각 피처에서 평균을 빼고, 표준편차로 나누어 표준화합니다.
iris_scaled = scaler.transform(iris_df)

# 7. 결과를 다시 DataFrame으로 변환
iris_df_scaled = pd.DataFrame(data=iris_scaled,
                              columns=iris.feature_names)

# (주피터 환경이라면 display(iris_df_scaled)로 일부 확인 가능)
print("스케일링 후 일부 데이터:\n", iris_df_scaled.head())

# 8. 스케일링 후 평균과 분산 확인
#   - 이론적으로 평균은 0에 가깝고, 분산은 1에 가깝게 됩니다.
print("스케일링 후 feature 평균값:\n", iris_df_scaled.mean())
print("스케일링 후 feature 분산값:\n", iris_df_scaled.var())

3-3. MinMaxScaler – 0~1 범위로 정규화

# -----------------------------------------------------------
# MinMaxScaler 예제: 0~1 범위로 스케일링
# -----------------------------------------------------------

from sklearn.preprocessing import MinMaxScaler
from sklearn.datasets import load_iris
import pandas as pd

# 1. 아이리스 데이터 로딩
iris = load_iris()
iris_data = iris.data

# 2. DataFrame으로 변환
iris_df = pd.DataFrame(data=iris_data,
                       columns=iris.feature_names)

# 3. MinMaxScaler 객체 생성
scaler = MinMaxScaler()

# 4. fit()으로 각 피처의 최소값, 최대값 학습
scaler.fit(iris_df)

# 5. transform()으로 스케일링 적용
#   - 각 피처를 (값 - 최소값) / (최대값 - 최소값) 형태로 변환합니다.
iris_scaled = scaler.transform(iris_df)

# 6. 변환 결과를 DataFrame으로 변환
iris_df_scaled = pd.DataFrame(data=iris_scaled,
                              columns=iris.feature_names)

# 7. 각 피처의 최소값, 최대값 확인
#   - 최소값은 0, 최대값은 1에 가깝게 변환됩니다.
print("MinMax 스케일링 후 feature 최소값:\n", iris_df_scaled.min())
print("MinMax 스케일링 후 feature 최대값:\n", iris_df_scaled.max())

 

이번 5편에서는 머신러닝 모델링 이전에 반드시 고려해야 할 데이터 전처리 기본기 중에서 다음 두 가지를 중심으로 살펴보았습니다.

  • 문자열 데이터를 숫자형으로 변환하는 데이터 인코딩 (레이블 인코딩, 원-핫 인코딩)
  • 피처의 크기를 맞추는 데이터 스케일링 (StandardScaler, MinMaxScaler)

이러한 전처리 작업은 단순한 “형식 맞추기”를 넘어서,
모델의 성능과 안정성을 크게 좌우하는 핵심 단계입니다.

특히 선형 모델, SVM, 신경망과 같이 스케일에 민감한 알고리즘에서는
스케일링 여부에 따라 정확도가 크게 달라질 수 있습니다.

앞으로 실제 프로젝트에서:

  • 범주형 컬럼은 → 레이블/원-핫 인코딩
  • 수치형 컬럼은 → 표준화 또는 정규화

를 자연스럽게 떠올릴 수 있으면, 머신러닝 파이프라인의 기본기를 갖추었다고 볼 수 있습니다.

반응형