컴퓨터과학 챕터 2 약 9분

Ch2. 머신러닝 — 분류 알고리즘과 모델 선택

O
OIYO 편집부 기여자
2/6

분류 문제란?

**분류(Classification)**는 입력 데이터가 어떤 **범주(클래스)**에 속하는지 예측하는 지도학습 문제입니다. 출력이 연속값이 아닌 이산적 레이블이라는 점에서 회귀와 구분됩니다.

회귀: "이 집의 가격은 얼마인가?" → 연속값 (예: 3억 2천만 원)
분류: "이 메일은 스팸인가?"      → 이산값 (예: 스팸 / 정상)

이진 분류 vs 다중 클래스 분류

이진 분류(Binary Classification): 클래스가 2개

출력: {0, 1} 또는 {음성, 양성}
예시:
  - 이메일: 스팸(1) vs 정상(0)
  - 의료: 양성(1) vs 음성(0)
  - 금융: 사기(1) vs 정상(0)

다중 클래스 분류(Multiclass Classification): 클래스가 3개 이상

출력: {0, 1, 2, ..., k}
예시:
  - 손글씨 숫자 인식: {0, 1, 2, ..., 9}
  - 꽃 품종 분류: {setosa, versicolor, virginica}
  - 언어 감지: {Korean, English, Japanese, ...}

로지스틱 회귀 (Logistic Regression)

이름은 “회귀”이지만 사실상 이진 분류를 위한 알고리즘입니다. 선형 결합값을 확률(0~1)로 변환하기 위해 시그모이드 함수를 사용합니다.

시그모이드 함수 (Sigmoid Function)

σ(z) = 1 / (1 + e^(-z))

입력값 z 범위: (-∞, +∞)
출력값 범위:   (0, 1) ← 확률로 해석 가능

z >> 0 → σ(z) → 1  (확실히 클래스 1)
z = 0  → σ(z) = 0.5 (결정 경계)
z << 0 → σ(z) → 0  (확실히 클래스 0)
로지스틱 회귀 모델:
z = θ₀ + θ₁x₁ + θ₂x₂ + ... + θₙxₙ
P(y=1|x) = σ(z) = 1 / (1 + e^(-z))

결정 경계(Decision Boundary):
P(y=1|x) ≥ 0.5 → y_hat = 1 (클래스 1 예측)
P(y=1|x) < 0.5 → y_hat = 0 (클래스 0 예측)

결정 경계 이해

결정 경계는 σ(z) = 0.5가 되는 지점, 즉 z = 0인 직선(또는 곡면)입니다.

단순 예시 (특성 2개):
θ₀ + θ₁x₁ + θ₂x₂ = 0

예: -3 + x₁ + x₂ = 0 → x₁ + x₂ = 3
→ 이 직선이 두 클래스를 구분하는 결정 경계

로지스틱 회귀는 선형 결정 경계만 표현 가능합니다. 비선형 경계가 필요하면 다항 특성 추가 또는 다른 알고리즘을 사용합니다.

비용함수: Log Loss (Cross-Entropy)

단일 샘플 비용:
L(y, ŷ) = -[y × log(ŷ) + (1-y) × log(1-ŷ)]

전체 비용함수:
J(θ) = -(1/m) × Σ [yᵢ×log(h(xᵢ)) + (1-yᵢ)×log(1-h(xᵢ))]

직관:
y=1이고 ŷ=1 → L=0 (완벽한 예측)
y=1이고 ŷ≈0 → L→∞ (최악의 예측, 큰 페널티)

의사결정나무 (Decision Tree)

의사결정나무는 데이터를 질문(조건)의 연속으로 분류하는 직관적인 알고리즘입니다. 전문 지식 없이도 결과를 해석할 수 있어 실무에서 널리 사용됩니다.

트리 구조 용어

루트 노드(Root Node): 가장 최상단 분할점 (전체 데이터)
내부 노드(Internal Node): 중간 분할점 (조건 포함)
리프 노드(Leaf Node): 최종 예측값이 있는 끝 노드
깊이(Depth): 루트에서 특정 노드까지의 거리

분할 기준: 불순도 (Impurity)

의사결정나무는 각 분할 후 노드의 불순도가 가장 많이 감소하는 방향으로 특성과 기준값을 선택합니다.

엔트로피 (Entropy):

H(S) = -Σ pᵢ × log₂(pᵢ)

pᵢ: 클래스 i의 비율

예시:
순수한 노드 (100% 클래스1): H = -(1×log₂1) = 0
50:50 혼합 노드:             H = -(0.5×log₂0.5 + 0.5×log₂0.5) = 1 (최대)

→ 엔트로피가 낮을수록 순수(좋은 분할)

정보이득 (Information Gain):

IG = H(부모) - [가중 평균 H(자식 노드)]

→ IG가 가장 큰 특성으로 분할
→ ID3, C4.5 알고리즘에서 사용

지니 불순도 (Gini Impurity):

Gini(S) = 1 - Σ pᵢ²

완전 순수: Gini = 0
50:50 혼합: Gini = 1 - (0.5² + 0.5²) = 0.5

→ scikit-learn 의사결정나무의 기본 기준
→ 계산이 엔트로피보다 빠름

과적합과 가지치기 (Pruning)

과적합된 트리:
→ 훈련 데이터의 모든 패턴(노이즈 포함)을 외워버림
→ 훈련 정확도 ~100%이지만 테스트 정확도 낮음

가지치기 방법:
1. 사전 가지치기 (Pre-pruning):
   - max_depth: 최대 깊이 제한
   - min_samples_split: 분할 최소 샘플 수
   - min_samples_leaf: 리프 최소 샘플 수

2. 사후 가지치기 (Post-pruning):
   - 트리를 완전히 성장시킨 후 필요 없는 가지 제거
from sklearn.tree import DecisionTreeClassifier

# 과적합 방지 파라미터 설정
clf = DecisionTreeClassifier(
    max_depth=5,            # 최대 깊이 5
    min_samples_split=20,   # 분할 최소 20개 샘플
    min_samples_leaf=10,    # 리프 최소 10개 샘플
    criterion='gini',       # 분할 기준: 지니 불순도
    random_state=42
)

앙상블 학습: 랜덤포레스트 (Random Forest)

단일 의사결정나무의 과적합 문제를 해결하기 위해 여러 트리를 결합하는 앙상블 방법입니다.

배깅 (Bagging, Bootstrap Aggregating)

랜덤포레스트 = 배깅 + 특성 무작위 선택

1단계: 부트스트랩 샘플링
→ 훈련 데이터(n개)에서 복원추출로 n개 샘플 선택
→ 각 트리마다 서로 다른 서브셋 사용
→ 전체 샘플의 약 63.2%만 선택됨 (나머지 36.8%는 OOB)

2단계: 특성 무작위 선택
→ 각 분할마다 전체 p개 특성 중 √p개 또는 log₂p개만 고려
→ 트리 간 다양성 확보 (다양성 = 앙상블 성능 향상의 열쇠)

3단계: 예측 집계
→ 분류: 다수결 투표 (Majority Voting)
→ 회귀: 평균값 (Averaging)

OOB (Out-Of-Bag) 오류: 부트스트랩에서 선택되지 않은 36.8% 샘플로 각 트리를 검증. 별도 검증 세트 없이 성능 추정 가능.

특성 중요도 (Feature Importance)

랜덤포레스트는 각 특성이 불순도 감소에 얼마나 기여하는지 측정하여 특성 중요도를 산출합니다.

from sklearn.ensemble import RandomForestClassifier
import matplotlib.pyplot as plt

rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)

# 특성 중요도 확인
importances = rf.feature_importances_
# 값이 클수록 중요한 특성

SVM (Support Vector Machine)

SVM은 클래스 간 마진(Margin)을 최대화하는 결정 경계를 찾는 분류 알고리즘입니다.

마진 최대화 직관

두 클래스 데이터 사이에 "도로"를 상상하세요:
→ 도로의 너비 = 마진
→ 마진이 클수록 새 데이터에 더 잘 일반화
→ SVM = 이 도로의 너비를 최대화하는 선 찾기

서포트 벡터(Support Vectors):
→ 결정 경계에 가장 가까이 있는 훈련 샘플들
→ 이 점들만이 결정 경계의 위치를 결정
→ 나머지 데이터 포인트는 영향 없음
하드 마진 SVM: 모든 샘플이 올바른 쪽에 분류되어야 함
→ 이상치에 매우 민감, 선형 분리 불가능 시 실패

소프트 마진 SVM: 일부 샘플의 마진 내 위치 허용
→ C 파라미터: 마진 위반 페널티
  C 크면 → 마진 작음, 과적합 가능
  C 작으면 → 마진 큼, 과소적합 가능

커널 트릭 (Kernel Trick)

비선형 데이터를 고차원 특성 공간으로 변환하면 선형 분리가 가능해집니다. 커널 트릭은 이 변환을 명시적으로 수행하지 않고도 내적(dot product)을 계산하는 방법입니다.

커널 함수 K(x, z) = φ(x)ᵀφ(z)
→ 고차원 변환 φ를 직접 계산하지 않고 커널 함수만 사용

주요 커널:
선형(Linear):       K(x, z) = xᵀz
다항(Polynomial):   K(x, z) = (γxᵀz + r)^d
RBF/Gaussian:       K(x, z) = exp(-γ||x-z||²) ← 가장 범용적
시그모이드(Sigmoid): K(x, z) = tanh(γxᵀz + r)

직관: RBF 커널은 각 훈련 샘플을 중심으로 하는 “방사형 기저 함수” 범위를 정의합니다. γ가 클수록 각 샘플의 영향 범위가 좁아집니다.

from sklearn.svm import SVC

# RBF 커널 SVM
svm = SVC(kernel='rbf', C=1.0, gamma='scale', random_state=42)
svm.fit(X_train, y_train)

모델 선택 기준: 편향-분산 트레이드오프

핵심 개념

모델 오류 = 편향² + 분산 + 불가피한 노이즈

편향(Bias):
→ 모델의 단순함으로 인한 체계적 오류
→ "실제 패턴을 제대로 포착하지 못함"
→ 과소적합 모델에서 높음

분산(Variance):
→ 훈련 데이터의 작은 변동에 모델이 과민하게 반응
→ "훈련 데이터 노이즈까지 외워버림"
→ 과적합 모델에서 높음
트레이드오프 관계:
모델 복잡도 ↑ → 편향 ↓, 분산 ↑ (과적합 방향)
모델 복잡도 ↓ → 편향 ↑, 분산 ↓ (과소적합 방향)

최적 지점 = 총 오류(편향² + 분산)가 최소인 모델 복잡도

알고리즘별 편향-분산 특성

알고리즘편향분산특징
선형/로지스틱 회귀높음낮음단순, 해석 쉬움
의사결정나무(깊은)낮음높음과적합 위험
랜덤포레스트낮음중간의사결정나무보다 분산 감소
SVM(RBF, 작은 C)높음낮음마진 크게, 규제 강함
SVM(RBF, 큰 C)낮음높음마진 작게, 과적합 위험

진단 방법: 학습 곡선

학습 곡선(Learning Curve): 훈련 크기 vs 오류 그래프

과소적합 진단:
→ 훈련 오류: 높음
→ 검증 오류: 높음 (훈련 오류에 근접)
→ 해결: 더 복잡한 모델, 특성 추가

과적합 진단:
→ 훈련 오류: 낮음
→ 검증 오류: 높음 (훈련 오류와 큰 차이)
→ 해결: 정규화, 데이터 추가, 단순한 모델

교차검증을 통한 모델 비교

여러 분류 알고리즘을 공정하게 비교할 때는 K-Fold 교차검증을 사용합니다.

from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC

models = {
    '로지스틱회귀': LogisticRegression(max_iter=1000),
    '의사결정나무': DecisionTreeClassifier(max_depth=5),
    '랜덤포레스트': RandomForestClassifier(n_estimators=100),
    'SVM (RBF)':   SVC(kernel='rbf', C=1.0)
}

for name, model in models.items():
    scores = cross_val_score(model, X, y, cv=5, scoring='f1')
    print(f"{name}: 평균 F1={scores.mean():.3f}, 표준편차={scores.std():.3f}")

모델 선택 기준:

1. 성능(정확도, F1 등): 예측 정확성
2. 해석가능성: 의사결정나무 > 로지스틱회귀 > 랜덤포레스트 > SVM
3. 훈련 속도: 로지스틱회귀 > 의사결정나무 > SVM > 랜덤포레스트
4. 데이터 크기: SVM은 대용량 데이터에서 느림
5. 특성 타입: 범주형 포함 시 의사결정나무·랜덤포레스트 유리

클래스 불균형 처리

실제 분류 문제에서는 클래스 비율이 극도로 불균형한 경우가 많습니다 (예: 사기 탐지에서 사기 거래가 0.1%).

불균형 데이터의 문제:
→ 모델이 다수 클래스만 예측해도 높은 정확도 달성
→ 예: 99% 정상, 1% 사기 → 모두 "정상" 예측 시 정확도 99%
→ 하지만 사기를 전혀 탐지 못함 (재현율=0)

처리 방법:

1. 오버샘플링 (SMOTE 등):
   → 소수 클래스 합성 샘플 생성
   → 데이터 양 증가

2. 언더샘플링:
   → 다수 클래스 일부만 사용
   → 데이터 양 감소 (정보 손실)

3. 가중치 부여:
   → 소수 클래스에 더 큰 비용 할당
   → class_weight='balanced' (scikit-learn)

4. 평가 지표 변경:
   → Accuracy 대신 F1, AUC-ROC, PR Curve 사용

핵심 개념 카드

로지스틱 회귀 결정 경계 ★★★★★ : σ(z) = 0.5인 지점이 결정 경계. z = θᵀx = 0이 선형 결정 경계. P ≥ 0.5 → 클래스 1 예측. 암기 포인트: Sigmoid 출력이 0.5를 기준으로 클래스 나눔

지니 불순도와 엔트로피 ★★★★★ : 지니 = 1-Σpᵢ², 엔트로피 = -Σpᵢlog₂pᵢ. 둘 다 순수도 측정. 완전 순수 노드 = 0. scikit-learn 기본값은 지니. 암기 포인트: 지니는 계산 빠름, 엔트로피는 로그 계산 필요

랜덤포레스트 = 배깅 + 특성 무작위 ★★★★★ : 복원추출로 다양한 서브셋, 분할 시 무작위 특성 선택. 트리 간 상관관계 감소 → 분산 감소 → 성능 향상. 암기 포인트: 다양성이 앙상블 성능의 핵심

SVM 마진 최대화 ★★★★☆ : 서포트 벡터(결정 경계에 가장 가까운 점)들 간 마진 최대화. 커널 트릭으로 비선형 분리 가능. 암기 포인트: 마진이 넓을수록 새 데이터에 더 잘 일반화

편향-분산 트레이드오프 ★★★★★ : 총 오류 = 편향² + 분산 + 노이즈. 복잡한 모델 = 낮은 편향·높은 분산. 단순한 모델 = 높은 편향·낮은 분산. 암기 포인트: 과적합=분산↑, 과소적합=편향↑


실전 퀴즈

Q1. 로지스틱 회귀가 이름에 ‘회귀’가 들어가지만 분류 알고리즘인 이유를 설명하라.

로지스틱 회귀는 선형 결합 z = θᵀx (회귀식)를 계산한 후, 시그모이드 함수를 통해 (0, 1) 범위의 확률로 변환합니다. 출력이 연속적 수치가 아닌 클래스 소속 확률이며, 0.5를 임계값으로 이진 클래스를 분류합니다. 따라서 회귀적 계산 방식을 사용하지만 목적은 분류입니다.

Q2. 의사결정나무에서 지니 불순도가 0인 노드는 어떤 상태인가?

지니 불순도 Gini = 1 - Σpᵢ² = 0이 되려면 하나의 클래스가 100%를 차지해야 합니다 (예: p₁=1, 나머지=0). 이는 **완전히 순수한 노드(Pure Node)**로, 해당 노드에 속하는 모든 샘플이 같은 클래스에 속한다는 의미입니다. 이 시점에서 분할을 멈추고 리프 노드로 결정합니다.

Q3. 클래스 불균형 데이터(정상 99%, 사기 1%)에서 정확도(Accuracy)가 좋지 않은 평가 지표인 이유는?

모든 샘플을 “정상”으로 예측하기만 해도 **정확도 99%**를 달성할 수 있습니다. 하지만 이 모델은 사기 거래를 하나도 탐지하지 못합니다(재현율=0). 클래스 불균형 상황에서는 F1 Score(정밀도와 재현율의 조화평균), AUC-ROC, 또는 소수 클래스에 집중한 Precision-Recall Curve를 평가 지표로 사용해야 모델의 실질적 성능을 올바르게 측정할 수 있습니다.

O

OIYO 편집부

Content Editor

지식 인큐베이터이자 전문 콘텐츠 크리에이터. 경영, 경제, 법률 및 실생활에 유용한 실무/자격증 중심의 깊이 있는 정보를 연구하고 공유합니다.