🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

분류 알고리즘 기초 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 12. 2. · 11 Views

분류 알고리즘 기초 완벽 가이드

머신러닝의 핵심인 분류 알고리즘을 초급 개발자도 쉽게 이해할 수 있도록 설명합니다. KNN, 로지스틱 회귀, 나이브 베이즈부터 하이퍼파라미터 튜닝과 시각화까지 실무에서 바로 활용할 수 있는 내용을 담았습니다.


목차

  1. 분류_문제_이해하기
  2. K-최근접_이웃_알고리즘
  3. 로지스틱_회귀_구현
  4. 나이브_베이즈_분류
  5. 하이퍼파라미터_튜닝_기초
  6. 분류_결과_시각화

1. 분류 문제 이해하기

김개발 씨는 이메일 서비스 회사에 입사한 지 한 달이 된 주니어 개발자입니다. 어느 날 팀장님이 다가와 말씀하셨습니다.

"김개발 씨, 스팸 메일을 자동으로 걸러내는 기능을 만들어볼래요?" 김개발 씨는 고민에 빠졌습니다. 수천 개의 이메일을 일일이 확인할 수도 없고, 단순한 키워드 필터로는 한계가 있었기 때문입니다.

**분류(Classification)**란 주어진 데이터를 미리 정해진 카테고리 중 하나로 구분하는 것입니다. 마치 우체국 직원이 편지를 지역별로 분류하는 것과 같습니다.

분류 알고리즘을 이해하면 스팸 필터, 질병 진단, 고객 이탈 예측 등 실무에서 만나는 다양한 문제를 해결할 수 있습니다.

다음 코드를 살펴봅시다.

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# 붓꽃 데이터 로드 - 대표적인 분류 문제 데이터셋
iris = load_iris()
X, y = iris.data, iris.target

# 학습용 데이터와 테스트용 데이터 분리
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# 데이터 형태 확인
print(f"학습 데이터: {X_train.shape}")  # (120, 4)
print(f"테스트 데이터: {X_test.shape}")  # (30, 4)
print(f"분류할 클래스: {iris.target_names}")  # 3종류의 붓꽃

김개발 씨는 입사 한 달 차 주니어 개발자입니다. 스팸 메일 필터링 기능을 맡게 되었지만, 어디서부터 시작해야 할지 막막했습니다.

단순히 특정 단어가 포함된 메일을 차단하는 방식으로는 정상 메일까지 걸러지는 문제가 발생했습니다. 선배 개발자 박시니어 씨가 조언해주었습니다.

"분류 알고리즘을 사용해보세요. 컴퓨터가 스스로 스팸의 패턴을 학습하게 하는 거예요." 그렇다면 분류란 정확히 무엇일까요?

쉽게 비유하자면, 분류는 마치 도서관 사서가 새로 들어온 책을 적절한 서가에 배치하는 것과 같습니다. 사서는 책의 제목, 저자, 내용을 살펴보고 문학, 과학, 역사 등의 카테고리 중 하나를 선택합니다.

분류 알고리즘도 마찬가지로 데이터의 특성을 분석하여 미리 정해진 범주 중 하나에 할당합니다. 분류 문제에는 크게 두 가지 유형이 있습니다.

첫 번째는 **이진 분류(Binary Classification)**입니다. 스팸인지 아닌지, 합격인지 불합격인지처럼 두 가지 중 하나를 선택하는 문제입니다.

두 번째는 **다중 분류(Multi-class Classification)**입니다. 과일 이미지를 보고 사과, 배, 오렌지 중 하나로 분류하는 것처럼 세 개 이상의 범주 중 하나를 선택합니다.

위의 코드를 살펴보겠습니다. 먼저 load_iris() 함수로 붓꽃 데이터셋을 불러옵니다.

이 데이터셋은 150개의 붓꽃 샘플을 담고 있으며, 각 샘플은 꽃잎 길이, 꽃잎 너비 등 4가지 특성을 가집니다. 이 특성들을 바탕으로 3종류의 붓꽃 중 어떤 종인지 분류하는 것이 목표입니다.

다음으로 train_test_split() 함수로 데이터를 나눕니다. 학습 데이터로 모델을 훈련시키고, 테스트 데이터로 모델의 성능을 검증합니다.

마치 시험 공부를 할 때 문제집으로 공부하고, 모의고사로 실력을 점검하는 것과 같습니다. 실제 현업에서는 어떻게 활용할까요?

금융 회사에서는 대출 신청자의 데이터를 분석하여 대출 승인 여부를 결정합니다. 병원에서는 환자의 검사 결과를 바탕으로 질병 유무를 판단합니다.

쇼핑몰에서는 고객의 행동 패턴을 분석하여 이탈 가능성을 예측합니다. 하지만 주의할 점도 있습니다.

분류 모델을 만들 때 가장 중요한 것은 데이터의 품질입니다. 잘못된 데이터로 학습하면 잘못된 결과가 나옵니다.

또한 클래스 간 데이터 비율이 심하게 불균형하면 모델이 편향될 수 있습니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.

박시니어 씨의 설명을 들은 김개발 씨는 분류 문제의 개념을 이해했습니다. "아, 컴퓨터가 스팸 메일의 특징을 학습해서 새로운 메일을 판단하게 하는 거군요!" 이제 분류의 기본 개념을 이해했으니, 실제로 분류를 수행하는 알고리즘들을 하나씩 살펴보겠습니다.

실전 팁

💡 - 분류 문제를 시작하기 전에 항상 클래스 분포를 확인하세요

  • 테스트 데이터는 전체의 20~30% 정도로 설정하는 것이 일반적입니다

2. K-최근접 이웃 알고리즘

김개발 씨는 첫 번째 분류 알고리즘을 배우게 되었습니다. 박시니어 씨가 칠판에 점들을 그리며 설명을 시작했습니다.

"새로운 데이터가 들어오면, 주변에 있는 이웃들을 살펴보고 다수결로 결정하는 거예요." 김개발 씨는 학창 시절 자리 배치를 떠올렸습니다. 조용한 학생들 사이에 앉으면 나도 조용해지고, 시끄러운 학생들 사이에 앉으면 나도 시끄러워지던 기억이요.

**KNN(K-Nearest Neighbors)**은 새로운 데이터가 주어지면 가장 가까운 K개의 이웃을 찾아 다수결로 클래스를 결정하는 알고리즘입니다. 마치 동네에 이사 왔을 때 이웃들을 보고 그 동네의 분위기를 파악하는 것과 같습니다.

직관적이고 이해하기 쉬워서 분류 알고리즘 입문용으로 많이 사용됩니다.

다음 코드를 살펴봅시다.

from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler

# 특성 스케일링 - KNN은 거리 기반이므로 스케일링 필수
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# KNN 모델 생성 - K=5로 설정
knn = KNeighborsClassifier(n_neighbors=5)

# 모델 학습
knn.fit(X_train_scaled, y_train)

# 예측 및 정확도 평가
y_pred = knn.predict(X_test_scaled)
accuracy = accuracy_score(y_test, y_pred)
print(f"KNN 정확도: {accuracy:.2%}")  # 약 96~100%

김개발 씨가 KNN을 처음 접했을 때, 알고리즘이라기보다는 상식에 가깝다고 느꼈습니다. "가까운 이웃을 보고 판단한다니, 너무 단순한 거 아닌가요?" 박시니어 씨가 웃으며 대답했습니다.

"단순하지만 강력해요. 실제로 많은 문제에서 좋은 성능을 보여주거든요." KNN의 작동 원리를 자세히 살펴보겠습니다.

새로운 데이터 포인트가 들어오면, KNN은 기존 학습 데이터 중에서 가장 가까운 K개의 점을 찾습니다. 그리고 그 K개의 이웃들이 어떤 클래스에 속하는지 확인한 뒤, 가장 많은 클래스로 새 데이터를 분류합니다.

예를 들어 K=5일 때, 이웃 5개 중 3개가 A 클래스이고 2개가 B 클래스라면, 새 데이터는 A 클래스로 분류됩니다. 여기서 K값의 선택이 중요합니다.

K가 너무 작으면 노이즈에 민감해집니다. K=1이면 단 하나의 이웃만 보고 결정하므로, 그 이웃이 잘못된 데이터라면 결과도 틀려집니다.

반대로 K가 너무 크면 경계가 흐려져서 세밀한 분류가 어려워집니다. 일반적으로 K는 홀수로 설정하여 동점 상황을 피합니다.

위의 코드에서 StandardScaler가 눈에 띕니다. KNN은 거리를 기반으로 작동하기 때문에, 특성의 스케일이 다르면 문제가 생깁니다.

예를 들어 키(150200cm)와 몸무게(40100kg)를 함께 사용한다면, 키의 차이가 거리 계산에서 훨씬 큰 영향을 미칩니다. StandardScaler는 모든 특성을 평균 0, 표준편차 1로 맞춰서 공정한 비교가 가능하게 합니다.

코드를 단계별로 살펴보겠습니다. 먼저 **fit_transform(X_train)**으로 학습 데이터의 평균과 표준편차를 계산하고 변환합니다.

테스트 데이터는 **transform(X_test)**만 사용합니다. 학습 데이터의 통계치를 그대로 적용해야 일관성이 유지됩니다.

**KNeighborsClassifier(n_neighbors=5)**로 K=5인 모델을 생성하고, **fit()**으로 학습시킵니다. KNN의 장점은 무엇일까요?

첫째, 이해하기 쉽습니다. 알고리즘의 작동 원리를 직관적으로 설명할 수 있습니다.

둘째, 학습 시간이 거의 없습니다. 데이터를 저장하기만 하면 되기 때문입니다.

셋째, 새로운 클래스가 추가되어도 재학습 없이 바로 적용할 수 있습니다. 하지만 단점도 있습니다.

예측할 때마다 모든 데이터와 거리를 계산해야 하므로, 데이터가 많으면 느려집니다. 또한 차원이 높아지면 거리 개념이 희미해지는 차원의 저주 문제가 발생합니다.

따라서 대용량 데이터나 고차원 데이터에는 적합하지 않습니다. 김개발 씨가 물었습니다.

"그럼 실제로 언제 KNN을 쓰면 좋을까요?" 박시니어 씨가 대답했습니다. "데이터가 많지 않고, 빠른 프로토타이핑이 필요할 때 좋아요.

추천 시스템에서 비슷한 사용자를 찾는 데도 많이 쓰입니다."

실전 팁

💡 - K값은 보통 3, 5, 7 등 홀수로 설정하세요

  • 거리 기반 알고리즘이므로 반드시 스케일링을 먼저 수행하세요

3. 로지스틱 회귀 구현

김개발 씨는 다음 알고리즘으로 로지스틱 회귀를 배우게 되었습니다. "회귀라고 하면 연속적인 값을 예측하는 건데, 왜 분류에 쓰이나요?" 박시니어 씨가 설명했습니다.

"이름 때문에 많이들 헷갈려해요. 로지스틱 회귀는 확률을 출력하는데, 그 확률을 기준으로 분류를 하는 거예요."

**로지스틱 회귀(Logistic Regression)**는 입력 데이터가 특정 클래스에 속할 확률을 계산하는 알고리즘입니다. 마치 의사가 검사 결과를 보고 "이 병에 걸렸을 확률이 80%입니다"라고 말하는 것과 같습니다.

확률 값을 제공하므로 결과를 해석하기 쉽고, 이진 분류의 대표적인 알고리즘입니다.

다음 코드를 살펴봅시다.

from sklearn.linear_model import LogisticRegression

# 로지스틱 회귀 모델 생성
log_reg = LogisticRegression(max_iter=200, random_state=42)

# 모델 학습 - 스케일링된 데이터 사용
log_reg.fit(X_train_scaled, y_train)

# 예측 및 확률 출력
y_pred = log_reg.predict(X_test_scaled)
y_prob = log_reg.predict_proba(X_test_scaled)

print(f"로지스틱 회귀 정확도: {accuracy_score(y_test, y_pred):.2%}")
# 첫 번째 샘플의 클래스별 확률 확인
print(f"첫 샘플 확률: {y_prob[0]}")  # [0.02, 0.15, 0.83] 형태

김개발 씨는 로지스틱 회귀라는 이름이 혼란스러웠습니다. 분명 분류 문제를 다루는데 왜 '회귀'라는 단어가 붙어있는 걸까요?

박시니어 씨가 역사적 배경을 설명해주었습니다. "로지스틱 회귀는 원래 0과 1 사이의 확률 값을 예측하는 모델이에요.

그래서 회귀라는 이름이 붙었죠. 하지만 그 확률을 기준으로 분류를 수행하니까 분류 알고리즘으로 분류됩니다." 로지스틱 회귀의 핵심은 시그모이드 함수입니다.

시그모이드 함수는 어떤 값이든 0과 1 사이로 변환해줍니다. 마치 온도계의 수은이 아무리 올라가도 눈금 끝을 넘지 못하는 것처럼요.

입력 값이 커지면 1에 가까워지고, 작아지면 0에 가까워집니다. 이 출력값을 확률로 해석할 수 있습니다.

모델이 학습하는 과정을 살펴보겠습니다. 로지스틱 회귀는 각 특성에 가중치를 부여합니다.

예를 들어 스팸 메일 분류에서 '무료', '당첨', '클릭' 같은 단어가 포함되어 있으면 스팸일 확률이 높아지도록 가중치를 조정합니다. 학습 과정에서 이 가중치들이 최적화됩니다.

위의 코드를 분석해보겠습니다. **LogisticRegression(max_iter=200)**에서 max_iter는 최적화를 위한 최대 반복 횟수입니다.

데이터가 복잡하면 더 많은 반복이 필요할 수 있습니다. **predict()**는 최종 클래스를 반환하고, **predict_proba()**는 각 클래스에 속할 확률을 반환합니다.

**predict_proba()**의 결과가 특히 유용합니다. 예를 들어 결과가 [0.02, 0.15, 0.83]이라면, 첫 번째 클래스일 확률 2%, 두 번째 클래스일 확률 15%, 세 번째 클래스일 확률 83%라는 뜻입니다.

단순히 "세 번째 클래스입니다"라고만 말하는 것보다, 얼마나 확신하는지까지 알 수 있습니다. 실무에서는 이 확률 값이 중요한 역할을 합니다.

의료 분야에서는 질병 확률이 50%를 넘으면 무조건 양성으로 판정하기보다, 30%만 넘어도 추가 검사를 권유할 수 있습니다. 금융 분야에서는 사기 확률에 따라 다른 수준의 조치를 취할 수 있습니다.

이처럼 확률 값을 활용하면 더 섬세한 의사결정이 가능합니다. 로지스틱 회귀의 장점은 명확합니다.

첫째, 결과를 해석하기 쉽습니다. 각 특성의 가중치를 보면 어떤 특성이 분류에 얼마나 영향을 미치는지 알 수 있습니다.

둘째, 확률 값을 제공합니다. 셋째, 학습과 예측이 빠릅니다.

김개발 씨가 물었습니다. "KNN이랑 로지스틱 회귀 중에 뭘 써야 할까요?" 박시니어 씨가 대답했습니다.

"결과의 이유를 설명해야 한다면 로지스틱 회귀가 좋아요. 가중치를 보여주면서 '이 특성이 이렇게 영향을 미쳤습니다'라고 말할 수 있거든요."

실전 팁

💡 - 이진 분류에서는 로지스틱 회귀를 기본 모델로 먼저 시도해보세요

  • predict_proba()를 활용하여 확률 기반 의사결정을 구현할 수 있습니다

4. 나이브 베이즈 분류

김개발 씨는 스팸 필터를 본격적으로 구현하기 위해 나이브 베이즈를 배우게 되었습니다. "이 알고리즘은 정말 '나이브(순진)'해요.

모든 특성이 서로 독립적이라고 가정하거든요." 박시니어 씨의 말에 김개발 씨가 의아해했습니다. "그런 순진한 가정으로 잘 작동하나요?" "놀랍게도 텍스트 분류에서는 최고 수준의 성능을 보여줍니다."

**나이브 베이즈(Naive Bayes)**는 베이즈 정리를 기반으로 각 특성이 독립적이라고 가정하는 분류 알고리즘입니다. 마치 탐정이 여러 단서를 조합해서 범인을 추리하되, 각 단서가 서로 영향을 주지 않는다고 가정하는 것과 같습니다.

특히 텍스트 분류, 스팸 필터링에서 뛰어난 성능을 발휘합니다.

다음 코드를 살펴봅시다.

from sklearn.naive_bayes import GaussianNB, MultinomialNB
from sklearn.feature_extraction.text import CountVectorizer

# 수치 데이터용 가우시안 나이브 베이즈
gnb = GaussianNB()
gnb.fit(X_train, y_train)
print(f"가우시안 NB 정확도: {gnb.score(X_test, y_test):.2%}")

# 텍스트 데이터 예시 - 스팸 분류
texts = ["무료 당첨 지금 클릭", "회의 일정 공유드립니다", "복권 당첨 축하"]
labels = [1, 0, 1]  # 1: 스팸, 0: 정상

# 텍스트를 숫자 벡터로 변환
vectorizer = CountVectorizer()
X_text = vectorizer.fit_transform(texts)

# 텍스트용 다항 나이브 베이즈
mnb = MultinomialNB()
mnb.fit(X_text, labels)

김개발 씨는 나이브 베이즈의 '나이브'라는 이름이 재미있다고 생각했습니다. 알고리즘에 '순진하다'라는 수식어가 붙다니요.

박시니어 씨가 설명을 시작했습니다. "나이브 베이즈는 모든 특성이 서로 독립적이라고 가정해요.

현실에서는 이 가정이 거의 맞지 않죠. 하지만 이 순진한 가정 덕분에 계산이 엄청나게 빨라지고, 실제로 좋은 결과를 내는 경우가 많아요." 나이브 베이즈의 원리를 이해하기 위해 베이즈 정리를 살펴보겠습니다.

베이즈 정리는 "이미 알고 있는 정보를 바탕으로 새로운 정보가 주어졌을 때 확률을 업데이트하는 방법"입니다. 예를 들어, 어떤 메일에 "무료"라는 단어가 있다고 가정해봅시다.

스팸 메일 중에 "무료"가 포함된 비율이 80%이고, 정상 메일 중에 "무료"가 포함된 비율이 5%라면, "무료"가 포함된 메일은 스팸일 가능성이 훨씬 높습니다. 나이브 베이즈는 이런 확률 계산을 모든 특성에 대해 수행합니다.

"무료"가 있으면 스팸 확률이 올라가고, "회의"가 있으면 정상 확률이 올라가고, "당첨"이 있으면 다시 스팸 확률이 올라갑니다. 이 모든 확률을 곱해서 최종 확률을 계산합니다.

여기서 "특성이 독립적"이라는 가정이 필요한 것입니다. 독립적이어야 확률을 단순히 곱할 수 있기 때문입니다.

코드에서 두 가지 나이브 베이즈를 볼 수 있습니다. GaussianNB는 특성이 연속적인 수치 데이터일 때 사용합니다.

붓꽃 데이터처럼 꽃잎 길이, 너비 등의 측정값을 다룰 때 적합합니다. MultinomialNB는 특성이 횟수나 빈도일 때 사용합니다.

텍스트에서 각 단어가 몇 번 등장했는지 세는 경우에 딱 맞습니다. CountVectorizer는 텍스트를 숫자로 변환해줍니다.

"무료 당첨 지금 클릭"이라는 문장이 있으면, 각 단어별로 등장 횟수를 세어 벡터로 만듭니다. 이렇게 하면 컴퓨터가 텍스트를 숫자로 이해할 수 있게 됩니다.

나이브 베이즈의 강점은 뚜렷합니다. 첫째, 매우 빠릅니다.

학습과 예측 모두 빠르기 때문에 대용량 데이터에도 적합합니다. 둘째, 적은 데이터로도 잘 작동합니다.

확률 기반이라 데이터가 많지 않아도 합리적인 추정이 가능합니다. 셋째, 텍스트 분류에 특화되어 있습니다.

스팸 필터, 감성 분석, 문서 분류에서 여전히 널리 사용됩니다. 물론 한계도 있습니다.

독립성 가정이 맞지 않으면 성능이 떨어질 수 있습니다. 또한 학습 데이터에 없는 특성이 테스트 데이터에 나타나면 확률이 0이 되는 문제가 있습니다.

이를 해결하기 위해 라플라스 스무딩이라는 기법을 사용합니다. 김개발 씨는 나이브 베이즈로 스팸 필터를 구현하기로 했습니다.

단순해 보이는 알고리즘이지만, 수십 년간 이메일 서비스에서 검증된 방법이었기 때문입니다.

실전 팁

💡 - 텍스트 분류에는 MultinomialNB를 먼저 시도해보세요

  • 학습 데이터가 적을 때 나이브 베이즈가 좋은 선택이 될 수 있습니다

5. 하이퍼파라미터 튜닝 기초

김개발 씨가 여러 알고리즘을 구현한 후, 박시니어 씨가 질문했습니다. "KNN에서 K를 5로 설정했는데, 왜 하필 5인가요?" 김개발 씨는 대답하지 못했습니다.

"그냥 기본값이라서요..." 박시니어 씨가 고개를 저었습니다. "K 값에 따라 성능이 크게 달라질 수 있어요.

최적의 값을 찾는 과정이 바로 하이퍼파라미터 튜닝입니다."

**하이퍼파라미터(Hyperparameter)**는 모델이 학습하기 전에 사람이 직접 설정해야 하는 값입니다. 마치 요리할 때 오븐 온도와 시간을 요리사가 결정하는 것과 같습니다.

하이퍼파라미터 튜닝은 여러 값을 시도해보고 가장 좋은 성능을 내는 조합을 찾는 과정입니다.

다음 코드를 살펴봅시다.

from sklearn.model_selection import GridSearchCV, cross_val_score

# KNN의 하이퍼파라미터 탐색 범위 설정
param_grid = {
    'n_neighbors': [3, 5, 7, 9, 11],  # K 값 후보
    'weights': ['uniform', 'distance'],  # 가중치 방식
    'metric': ['euclidean', 'manhattan']  # 거리 측정 방식
}

# GridSearchCV로 최적 파라미터 탐색
grid_search = GridSearchCV(
    KNeighborsClassifier(),
    param_grid,
    cv=5,  # 5-폴드 교차 검증
    scoring='accuracy'
)

grid_search.fit(X_train_scaled, y_train)
print(f"최적 파라미터: {grid_search.best_params_}")
print(f"최고 정확도: {grid_search.best_score_:.2%}")

김개발 씨는 하이퍼파라미터라는 용어가 낯설었습니다. 파라미터와 뭐가 다른 걸까요?

박시니어 씨가 차이점을 설명했습니다. "파라미터는 모델이 학습하면서 스스로 결정하는 값이에요.

로지스틱 회귀의 가중치 같은 거죠. 반면 하이퍼파라미터는 학습 전에 우리가 직접 정해줘야 하는 값이에요.

KNN의 K 값, 로지스틱 회귀의 반복 횟수 같은 것들이죠." 하이퍼파라미터를 잘못 설정하면 어떻게 될까요? KNN에서 K=1로 설정하면 노이즈에 너무 민감해지고, K=100으로 설정하면 세부적인 패턴을 놓치게 됩니다.

로지스틱 회귀에서 반복 횟수가 너무 적으면 최적화가 덜 되고, 너무 많으면 시간만 낭비됩니다. 적절한 값을 찾아야 최고의 성능을 얻을 수 있습니다.

GridSearchCV는 이 과정을 자동화해줍니다. Grid는 격자를 의미합니다.

탐색할 하이퍼파라미터 값들을 격자처럼 나열하고, 모든 조합을 시도해봅니다. 위 코드에서는 K 값 5개, 가중치 방식 2개, 거리 측정 방식 2개를 조합하므로 총 5 x 2 x 2 = 20가지 조합을 시험합니다.

cv=55-폴드 교차 검증을 의미합니다. 데이터를 5등분하여, 4개로 학습하고 1개로 검증하는 과정을 5번 반복합니다.

이렇게 하면 특정 데이터 분할에 운 좋게 잘 맞는 경우를 피하고, 더 신뢰할 수 있는 성능 평가가 가능합니다. 마치 시험을 한 번만 보는 것보다 여러 번 보고 평균을 내는 것이 더 정확한 것과 같습니다.

코드의 실행 결과를 살펴보겠습니다. best_params_는 가장 좋은 성능을 낸 하이퍼파라미터 조합을 알려줍니다.

best_score_는 그때의 교차 검증 점수입니다. 이 정보를 바탕으로 최종 모델을 구성하면 됩니다.

GridSearchCV의 단점도 있습니다. 모든 조합을 다 시도하기 때문에, 탐색 범위가 넓으면 시간이 오래 걸립니다.

이런 경우 RandomizedSearchCV를 사용할 수 있습니다. 모든 조합을 시도하는 대신, 무작위로 일부만 선택하여 탐색합니다.

시간은 줄어들지만 최적값을 놓칠 수도 있습니다. 실무에서는 어떻게 접근할까요?

먼저 넓은 범위에서 대략적인 최적값을 찾고, 그 주변에서 더 세밀하게 탐색하는 방식을 많이 사용합니다. 예를 들어 K를 [1, 10, 50, 100]으로 먼저 탐색해서 10 근처가 좋다는 것을 알아낸 후, [7, 8, 9, 10, 11, 12, 13]으로 다시 탐색하는 식입니다.

김개발 씨는 GridSearchCV를 돌려보고 K=7, 가중치는 distance, 거리는 euclidean이 최적이라는 결과를 얻었습니다. 기본값인 K=5보다 정확도가 2%나 높았습니다.

실전 팁

💡 - 처음에는 넓은 범위로 탐색하고, 점차 좁혀가는 전략을 사용하세요

  • 교차 검증 횟수(cv)는 데이터가 적으면 10, 많으면 5가 적당합니다

6. 분류 결과 시각화

김개발 씨가 모델을 완성하고 정확도가 95%라고 보고하자, 팀장님이 물었습니다. "95%라고 하셨는데, 어떤 클래스에서 잘 맞고 어떤 클래스에서 틀리나요?" 김개발 씨는 대답하지 못했습니다.

정확도 숫자 하나만으로는 모델의 성능을 제대로 이해할 수 없었던 것입니다. 박시니어 씨가 다가와 말했습니다.

"시각화가 필요해요. 혼동 행렬부터 그려볼까요?"

분류 결과 시각화는 모델이 어떤 예측을 잘하고 어떤 예측을 틀리는지 한눈에 보여주는 기법입니다. **혼동 행렬(Confusion Matrix)**은 실제 값과 예측 값의 관계를 표로 보여주고, **결정 경계(Decision Boundary)**는 모델이 데이터를 어떻게 나누는지 시각적으로 표현합니다.

다음 코드를 살펴봅시다.

import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
from sklearn.metrics import classification_report

# 혼동 행렬 생성 및 시각화
cm = confusion_matrix(y_test, y_pred)
disp = ConfusionMatrixDisplay(cm, display_labels=iris.target_names)
disp.plot(cmap='Blues')
plt.title('Classification Confusion Matrix')
plt.savefig('confusion_matrix.png')
plt.show()

# 상세 분류 리포트 출력
print(classification_report(y_test, y_pred,
                            target_names=iris.target_names))
# precision, recall, f1-score가 클래스별로 출력됨

김개발 씨는 시각화의 중요성을 깨달았습니다. 정확도가 95%라고 해도, 100개 중 5개를 틀린 건데 그 5개가 모두 특정 클래스에 집중되어 있다면 문제가 심각할 수 있습니다.

박시니어 씨가 혼동 행렬을 설명했습니다. 혼동 행렬은 실제 클래스와 예측 클래스를 2차원 표로 보여줍니다.

행은 실제 값, 열은 예측 값을 나타냅니다. 대각선에 있는 숫자는 올바르게 분류된 개수이고, 대각선 밖의 숫자는 잘못 분류된 개수입니다.

이 표를 보면 어떤 클래스를 어떤 클래스로 잘못 분류하는지 한눈에 알 수 있습니다. 예를 들어 스팸 필터에서 혼동 행렬을 살펴보면 중요한 정보를 얻을 수 있습니다.

정상 메일을 스팸으로 잘못 분류하는 경우(False Positive)는 사용자가 중요한 메일을 못 받게 됩니다. 스팸을 정상으로 잘못 분류하는 경우(False Negative)는 사용자가 스팸을 받게 됩니다.

어떤 실수가 더 치명적인지에 따라 모델을 조정해야 합니다. classification_report는 더 자세한 정보를 제공합니다.

**Precision(정밀도)**은 모델이 양성이라고 예측한 것 중 실제로 양성인 비율입니다. "스팸이라고 판단한 메일 중 실제 스팸의 비율"입니다.

**Recall(재현율)**은 실제 양성 중에서 모델이 양성이라고 맞춘 비율입니다. "실제 스팸 중에서 걸러낸 비율"입니다.

F1-score는 정밀도와 재현율의 조화 평균입니다. 코드를 살펴보겠습니다.

**confusion_matrix(y_test, y_pred)**로 혼동 행렬을 생성합니다. ConfusionMatrixDisplay로 시각화하고, **cmap='Blues'**로 색상을 지정합니다.

숫자가 클수록 진한 파란색으로 표시되어 직관적으로 파악할 수 있습니다. 결정 경계 시각화도 유용합니다.

결정 경계는 모델이 데이터를 어떻게 나누는지 보여줍니다. 2차원 평면에 데이터 점들을 찍고, 모델이 각 영역을 어떤 클래스로 분류하는지 색으로 표시합니다.

KNN은 복잡하고 구불구불한 경계를 만들고, 로지스틱 회귀는 직선 경계를 만드는 것을 시각적으로 확인할 수 있습니다. 실무에서 시각화는 여러 용도로 활용됩니다.

첫째, 모델 디버깅에 사용합니다. 특정 클래스에서 성능이 나쁘다면 그 클래스의 데이터를 더 수집하거나 특성을 추가할 수 있습니다.

둘째, 비개발자와의 소통에 활용합니다. 숫자보다 그림이 이해하기 쉽습니다.

셋째, 보고서 작성에 포함합니다. 모델의 성능을 객관적으로 보여줄 수 있습니다.

김개발 씨는 혼동 행렬을 그려보고 깜짝 놀랐습니다. 정확도는 95%였지만, 특정 꽃 종류에서는 30%만 맞추고 있었던 것입니다.

전체 정확도에 가려져 있던 문제점을 발견한 순간이었습니다. 팀장님에게 혼동 행렬과 분류 리포트를 보여주자, 팀장님이 만족하며 말했습니다.

"이제 어디를 개선해야 할지 알겠네요. 좋은 분석이에요."

실전 팁

💡 - 혼동 행렬은 분류 모델 평가에서 가장 먼저 확인해야 할 도구입니다

  • 불균형 데이터에서는 정확도보다 F1-score를 더 중요하게 보세요

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Python#Classification#KNN#LogisticRegression#NaiveBayes#Machine Learning,Python

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.