python, 전처리, 통계, 가설검정, 기계학습, 회귀, 분류, 군집, 모델 학습, 모델 평가
연속형 데이터 범주화(Discretization 또는 Binning)는 연속형 변수를 구간별로 나누어 범주형 변수로 변환하는 과정이다. 이 과정은 정보 손실을 수반하지만, 모델의 해석력을 높이고 비선형 관계를 단순화하며 노이즈를 감소시키는 효과가 있다. 특히 도메인 전문가와의 커뮤니케이션이나 규칙 기반 의사결정 시스템에서 유용하다. 이 장에서는 등간격 구간화, 등빈도 구간화, 사용자 정의 구간화, k-means 기반 구간화, Decision Tree 기반 구간화 등 다양한 범주화 기법을 학습한다.
예제: 데이터 로드
import pandas as pdimport seaborn as snsimport numpy as np# 데이터 로드df = sns.load_dataset("penguins")# 연속형 변수 확인print("연속형 변수 기초 통계:")print(df[["bill_length_mm", "bill_depth_mm", "flipper_length_mm", "body_mass_g"]].describe())
연속형 변수 기초 통계:
bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
count 342.000000 342.000000 342.000000 342.000000
mean 43.921930 17.151170 200.915205 4201.754386
std 5.459584 1.974793 14.061714 801.954536
min 32.100000 13.100000 172.000000 2700.000000
25% 39.225000 15.600000 190.000000 3550.000000
50% 44.450000 17.300000 197.000000 4050.000000
75% 48.500000 18.700000 213.000000 4750.000000
max 59.600000 21.500000 231.000000 6300.000000
8.1 범주화의 필요성과 효과
연속형 데이터를 범주화하면 다음과 같은 효과를 얻을 수 있다.
범주화의 주요 효과
효과
설명
예시
해석력 증가
숫자 대신 의미 있는 구간명 사용
“40.5mm” → “보통 길이”
노이즈 감소
작은 변동을 무시하고 큰 패턴에 집중
측정 오차 완화
비선형 관계 단순화
복잡한 관계를 구간별 규칙으로 표현
나이-위험도 관계
이상치 영향 완화
극단값을 구간 경계로 제한
최상위 구간으로 포함
규칙 추출 용이
의사결정 규칙 명확화
“A구간이면 승인”
다만, 정보 손실이 불가피하므로 데이터가 충분히 많고 모델의 예측 성능보다 해석력이 중요한 경우에 사용하는 것이 적절하다.
8.2 등간격 구간화 (Equal-width Binning)
등간격 구간화는 전체 값의 범위를 동일한 간격으로 k개의 구간으로 나누는 방법이다. 구현이 간단하고 직관적이지만, 데이터의 분포를 고려하지 않으므로 일부 구간에 데이터가 몰리거나 거의 없을 수 있다.
# 구간에 의미 있는 이름 부여df["bill_length_bin"] = pd.cut( df["bill_length_mm"], bins=4, labels=["짧음", "보통", "김", "매우 김"])print("라벨이 지정된 구간화 결과:")print(df["bill_length_bin"].value_counts())
라벨이 지정된 구간화 결과:
bill_length_bin
김 129
보통 124
짧음 79
매우 김 10
Name: count, dtype: int64
등빈도 구간화는 각 구간에 동일한 개수의 데이터가 포함되도록 분할하는 방법이다. 데이터의 분포를 고려하여 구간을 나누므로, 등간격 구간화의 불균형 문제를 해결할 수 있다.
예제: 등빈도 구간화
# 4개의 등빈도 구간으로 분할 (사분위수)df["bill_length_qbin"] = pd.qcut( df["bill_length_mm"], q=4)print("등빈도 구간화 결과:")print(df["bill_length_qbin"].value_counts().sort_index())print("\n각 구간의 데이터 개수:")for bin_range in df["bill_length_qbin"].unique(): count = (df["bill_length_qbin"] == bin_range).sum()print(f"{bin_range}: {count}개")
사용자 정의 구간화는 도메인 지식이나 비즈니스 규칙에 따라 직접 구간 경계를 설정하는 방법이다. 가장 해석력이 높지만, 주관이 개입되므로 기준에 대한 명확한 설명이 필요하다.
예제: 도메인 지식 기반 구간화
# 도메인 전문가가 정의한 구간 경계bins = [30, 40, 45, 50, 60]labels = ["매우 짧음", "짧음", "보통", "김"]df["bill_length_custom"] = pd.cut( df["bill_length_mm"], bins=bins, labels=labels)print("사용자 정의 구간화 결과:")print(df["bill_length_custom"].value_counts())# 구간 통계print("\n구간별 평균 체중:")print(df.groupby("bill_length_custom")["body_mass_g"].mean())
사용자 정의 구간화 결과:
bill_length_custom
보통 113
매우 짧음 100
짧음 77
김 52
Name: count, dtype: int64
구간별 평균 체중:
bill_length_custom
매우 짧음 3558.000000
짧음 4114.935065
보통 4657.079646
김 4578.846154
Name: body_mass_g, dtype: float64
장단점
장점
단점
해석력이 가장 높음
주관이 개입될 수 있음
도메인 지식을 직접 반영
데이터 분포를 무시할 수 있음
비즈니스 규칙과 일치
구간 설정 근거 설명 필요
적용 상황
명확한 도메인 기준이 있는 경우 (예: 의학적 기준, 법적 기준)
비즈니스 규칙이 정해진 경우 (예: 신용등급, 고객 등급)
기존 시스템과의 호환성이 필요한 경우
8.5 k-means 기반 구간화
k-means 기반 구간화는 값의 분포를 고려하여 군집 중심을 기준으로 구간을 나누는 방법이다. 비선형적인 데이터 구조를 반영할 수 있어 복잡한 분포에서도 효과적이다.
예제: k-means 기반 구간화
from sklearn.cluster import KMeans# 결측치 제거x = df[["bill_length_mm"]].dropna()# k-means 군집화 (3개 구간)kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)clusters = kmeans.fit_predict(x)# 원본 데이터프레임에 결과 저장df.loc[x.index, "bill_length_kbin"] = clustersprint("k-means 기반 구간화 결과:")print(df["bill_length_kbin"].value_counts().sort_index())# 각 군집의 중심값print("\n군집 중심값:")for i, center inenumerate(kmeans.cluster_centers_):print(f"군집 {i}: {center[0]:.2f}mm")# 군집별 통계print("\n군집별 범위:")for i inrange(3): cluster_data = x[clusters == i]print(f"군집 {i}: {cluster_data['bill_length_mm'].min():.2f} ~ {cluster_data['bill_length_mm'].max():.2f}mm")
Decision Tree 기반 구간화는 타겟 변수를 기준으로 정보이득을 최대화하는 구간을 찾는 지도학습 방법이다. 타겟과의 관계를 직접 반영하므로 예측 모델에 효과적이지만, 데이터 누수에 주의해야 한다.
예제: 타겟 기반 구간화
from sklearn.tree import DecisionTreeRegressor# 결측치 제거x = df[["bill_length_mm"]].dropna()y = df.loc[x.index, "body_mass_g"]# Decision Tree로 최적 구간 찾기tree = DecisionTreeRegressor( max_leaf_nodes=4, # 4개 구간 random_state=42)tree.fit(x, y)# 리프 노드 ID를 구간으로 사용df.loc[x.index, "bill_length_treebin"] = tree.apply(x)print("Decision Tree 기반 구간화 결과:")print(df["bill_length_treebin"].value_counts().sort_index())# 각 구간의 타겟 평균print("\n구간별 평균 체중:")print(df.groupby("bill_length_treebin")["body_mass_g"].mean().sort_index())# 구간 경계 확인 (트리 분할 지점)print("\n트리 분할 정보:")print(f"사용된 특성: {tree.feature_importances_}")
Decision Tree 기반 구간화 결과:
bill_length_treebin
3.0 82
4.0 65
5.0 88
6.0 107
Name: count, dtype: int64
구간별 평균 체중:
bill_length_treebin
3.0 3480.792683
4.0 3901.923077
5.0 4406.534091
6.0 4767.990654
Name: body_mass_g, dtype: float64
트리 분할 정보:
사용된 특성: [1.]
데이터 누수 주의
Decision Tree 기반 구간화는 타겟 정보를 사용하므로, 반드시 학습 데이터로만 구간을 결정하고 테스트 데이터에 적용해야 한다.
예제: 데이터 누수 방지
from sklearn.model_selection import train_test_split# 학습/테스트 분리df_clean = df[["bill_length_mm", "body_mass_g"]].dropna()X_train, X_test, y_train, y_test = train_test_split( df_clean[["bill_length_mm"]], df_clean["body_mass_g"], test_size=0.2, random_state=42)# 학습 데이터로만 트리 학습tree_safe = DecisionTreeRegressor(max_leaf_nodes=4, random_state=42)tree_safe.fit(X_train, y_train)# 학습/테스트 데이터에 동일한 구간 적용train_bins = tree_safe.apply(X_train)test_bins = tree_safe.apply(X_test)print("학습 데이터 구간 분포:")print(pd.Series(train_bins).value_counts().sort_index())print("\n테스트 데이터 구간 분포:")print(pd.Series(test_bins).value_counts().sort_index())
학습 데이터 구간 분포:
3 66
4 50
5 68
6 89
Name: count, dtype: int64
테스트 데이터 구간 분포:
3 16
4 18
5 17
6 18
Name: count, dtype: int64
장단점
장점
단점
타겟 정보를 직접 반영
데이터 누수 위험 (주의 필요)
예측 성능 향상 가능
과적합 위험
비선형 관계 포착
해석이 복잡할 수 있음
적용 상황
예측 모델의 성능이 중요한 경우
타겟과의 비선형 관계가 예상되는 경우
특성 공학(feature engineering)의 일환으로 사용
8.7 범주화 후 인코딩 연결
범주화된 변수는 여전히 범주형이므로, 모델 학습을 위해 인코딩이 필요하다.
예제: 범주화 후 One-Hot Encoding
# 범주화된 변수를 One-Hot Encodingdf_bin_encoded = pd.get_dummies( df, columns=["bill_length_bin"], drop_first=True)print("인코딩된 컬럼:")print([col for col in df_bin_encoded.columns if"bill_length_bin"in col])print("\n인코딩 결과 샘플:")print(df_bin_encoded.filter(like='bill_length_bin').head())
범주화와 인코딩을 조합하면 연속형 변수를 비선형적으로 활용하면서도 선형 모델에 적용할 수 있다.
8.8 범주화 vs 스케일링
범주화와 스케일링은 서로 다른 목적과 효과를 가진 전처리 방법이다.
범주화와 스케일링 비교
항목
스케일링
범주화
목적
변수 간 크기 통일
연속형을 범주형으로 변환
정보 손실
없음 (변환만)
있음 (구간화로 인한 손실)
해석력
낮음 (숫자 그대로)
높음 (의미 있는 구간명)
모델 안정성
보통
높음 (노이즈 감소)
주 용도
거리 기반 모델, 경사하강법
규칙 기반 의사결정, 해석
적합 모델
선형, KNN, SVM, 신경망
트리, 규칙 기반 시스템
선택 기준
예측 성능 우선: 스케일링 사용 (정보 손실 없음)
해석력 우선: 범주화 사용 (도메인 전문가 커뮤니케이션)
노이즈가 많은 경우: 범주화 고려 (노이즈 감소 효과)
데이터 충분: 스케일링 사용 (범주화는 정보 손실)
규칙 추출 필요: 범주화 사용 (명확한 의사결정 규칙)
8.9 요약
이 장에서는 연속형 데이터를 범주형으로 변환하는 다양한 범주화 기법을 학습했다. 주요 내용은 다음과 같다.
범주화 방법 비교
방법
원리
장점
단점
적용 상황
등간격
동일한 구간 너비
간단, 직관적
데이터 불균형
균등 분포, 도메인 기준 너비
등빈도
동일한 데이터 개수
분포 반영, 균형
너비 불균등, 중복값 문제
편향 분포, 순위 기반 분석
사용자 정의
도메인 지식 기반
해석력 최고, 비즈니스 반영
주관 개입, 근거 필요
명확한 기준 존재
k-means
군집 중심 기반
비선형 구조 반영
해석 어려움, 변동성
복잡한 분포, 자동화
Decision Tree
타겟 정보이득 기반
타겟 관계 반영, 성능 향상
데이터 누수 위험, 과적합
예측 성능 중요, 비선형 관계
범주화 적용 상황
상황
범주화 권장 여부
이유
모델 해석이 중요할 때
✓
의미 있는 구간명으로 설명 가능
비선형 관계 단순화
✓
복잡한 관계를 구간별 규칙으로 표현
데이터 노이즈가 큼
✓
작은 변동 무시, 큰 패턴 포착
데이터가 충분히 많음
✗
정보 손실이 아까움, 스케일링 선호
딥러닝 사용
✗
연속형 그대로 사용이 더 효과적
규칙 추출 필요
✓
명확한 의사결정 규칙 생성
범주화 의사결정 프로세스
EDA 수행: 데이터 분포, 타겟과의 관계 파악
목적 확인: 예측 성능 vs 해석력 중 무엇이 우선인지 결정
방법 선택: 상황에 맞는 범주화 방법 선택
검증: 범주화 전후 모델 성능 및 해석력 비교
문서화: 구간 설정 근거와 결과 명확히 기록
범주화는 정보 손실을 감수하고 해석력을 얻는 선택이다. EDA 결과를 바탕으로 신중하게 결정해야 하며, 특히 도메인 전문가와의 협업이 중요한 경우 사용자 정의 구간화를 고려해야 한다. 다음 단계로는 범주화된 변수를 인코딩하여 모델에 적용하거나, 스케일링을 통해 연속형 변수를 그대로 활용하는 방법을 선택할 수 있다.