251212_BootCamp Day 40_분류분석

2025. 12. 12. 20:08TIL

1. 분류분석(Classification Analysis)이란?

독립변수(X)를 통해 종속변수(Y)의 범주를 예측하는 분석 방식

종속변수가 범주형 변수이기 때문에, 독립변수(들)의 변화에 따라 종속변수가 어떤 범주(그룹)에 속하는 지 확인할 수 있다.

  • 하루 10회 접속 + 하루 시청 시간이 4시간➡️구독[Yes]
  • 하루 2회 접속 + 하루 시청 시간이 30➡️구독 X[No]

또한 특정 그룹에 속할 확률을 함께 확인할 수 있다.

  • 하루 10회 접속 + 하루 시청 시간이 4시간➡️Yes 확률 95%
  • 하루 2회 접속 + 하루 시청 시간이 30➡️Yes 확률 22%

즉 결정 경계(분류 기준)를 통해 데이터를 이진형(Yes/No) 또는 범주형(순위가 없는 범주)으로 분류하는 것이 분류분석의 큰 목적!

 

2. 로지스틱 회귀 (Logistic Regression)

독립변수와 종속변수의 관계를 선형식으로 만들고, 선형식을 0~1 사이의 범위를 갖는 함수로 변환해 확률을 추정하는 모델

Yes / No 일 확률을 예측한 다음, 기준(threshold, 임계점)보다 그 확률이 높으면 1(Yes), 낮으면 0(No)으로 분류

➡️실무에서는 고객 이탈 예측, 구독 여부 예측, 고장 예측, 질병 진단 등에 사용할 수 있다.

로지스틱 회귀의 종류

이진 로지스틱 회귀  종속변수가 두 가지 중 하나의 값을 가지는 경우 (이산형)
다중 로지스틱 회귀  종속변수가 순서가 없는 3개 이상인 경우 (범주형)

로지스틱 회귀의 원리

1) 범주를 0/1로 매핑

보통의 경우 Yes = 1, No = 0으로 매칭 (반드시 Yes = 1일 필요는 없음)

Yes = 1로 했을 때, 모델이 예측하는 확률 p는 Yes일 확률

2) 독립변수들을 선형식으로 결합

\(z=\beta_{0}+\beta_{1}x_{1}+\beta_{2}x_2+\cdots\)

z : 선형예측자

\(\beta_{0}, \beta_{1}, \beta_{2}\) : 가중치

\(x_{1}, x_{2}, x_{3}\) : 독립변수의 값

3) 시그모이드 함수(Sigmoid Function) 변환

선형식을 0 ~ 1 사이의 확률값으로 바꿔주는 시그모이드 함수로 변환

\(p(a)=\frac{1}{1+e^{-z}}\)

z: 2)에서 만든 선형식

https://ai.plainenglish.io/binary-classification-with-logistic-regression-3e4e6f177def

독립변수(X)에 따른 선형예측차 (z)의 변화에 따른 확률 p(a)의 값이 나오게 된다.

이때 결정경계(Decision Bound)를 넘는 p(a)는 1(Yes)로, 그렇지 않은 p(a)는 0(No)로 분류한다.

일반적인 결정경계는 0.5이지만, 상황에 따라 적절한 파라미터로 조정할 수 있다.

 

3. K-NN (K-Nearest Neighbors)

https://ai.plainenglish.io/introduction-to-k-nearest-neighbors-knn-algorithm-e8617a448fa8

K-최근접 이웃, 머신러닝의 분류 모델 중 하나로, 거리를 기반으로 유사한 경향을 보이는 각 데이터포인트를 묶어 분류

데이터포인트 간의 거리가 가까운 경우 한 class로 묶인다.

어떤 class에도 포함되지 않은 값➡️모든 값들과 멀리 떨어진 값➡️이상치

따라서 K-NN은 이상치 처리에 활용 가능하다.

K-NN의 거리 측정 방법에는 크게 유클리드 거리와 맨해튼 거리가 있다.

두 점 \(x(a, b), y(c, d)\)에 대해

유클리드 거리(Euclidean Distance) = \(\sqrt{(b-a)^2+(d-c)^2}\)

맨해탄 거리(Manhattan Distance) = \(|b-a|+|d-c|\)

K-NN은 거리 기반 머신러닝 모델이기 때문에, 거리 기준을 만들기 위해 표준화 또는 정규화가 반드시 필요하다.

Scikit-learn의 KNeighborsClassifier 함수를 이용해 K-NN 모델을 만들 수 있다.

import pandas as pd
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import classification_report
df = pd.read_csv("waterQuality1.csv")
# ammonia 컬럼에 #NUM!으로 기록되어 있는 행 제거
df2 = df.copy()
df2['ammonia'].value_counts()['#NUM!']
df2 = df2[df2['ammonia'].str.contains('#NUM!') == False]
df2.dropna(inplace=True)
# object형 컬럼 numeric으로 변환
df2['ammonia'] = pd.to_numeric(df2['ammonia'])
df2['is_safe'] = pd.to_numeric(df2['is_safe'])
# 독립변수(X) : 물 내부 원소 농도
# 종속변수(y) : 물이 안전한지 여부 (1:안전한 물, 0:안전하지 않은 물)
columns = df2.columns
columns = [c for c in columns if c not in ['is_safe']]
y = df2['is_safe']
X = df2[columns]
# 머신러닝 학습을 위한 test 데이터와 train 데이터 분리
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
X_train.shape, X_test.shape, y_train.shape, y_test.shape
# K-NN에 적용하기 전, train 데이터와 test 데이터 표준화 진행
sc = StandardScaler()
sc.fit(X_train)
X_train_std = sc.transform(X_train)
X_test_std = sc.transform(X_test)
# K-NN 모델 호출 후 train 데이터에 적용
knn = KNeighborsClassifier()
knnc = knn.fit(X_train, y_train)
# 테스트 데이터셋 예측
y_pred_knnc = knnc.predict(X_test)
y_pred_knnc
# 결과 확인
print(classification_report(y_test, y_pred_knnc))

K-NN 모델 예측 결과

Precision(정밀도) : 예측한 클래스 중 실제로 해당 클래스인 데이터의 비율
Recall(재현율) : 실제 클래스 중 예측한 클래스와 일치한 데이터의 비율
F1-score : Precision과 Recall의 조화평균
Support : 각 클래스의 실제 데이터 수
Accuracy : 모델의 분류 정확도
이 모델의 경우, 데이터 불균형(1이 0에 비해 매우 적임)으로 인해 안전한 물에 대한 예측 정확도가 낮게 측정됨.
Class 1(안전한 물)에 대한 recall이 0.11이라는 것은, 실제 1인 데이터 중 모델이 1로 예측한 것이 11%밖에 되지 않는다는 의미.
이처럼 데이터가 불균형한 경우, 데이터가 적은 class에 대해 머신러닝 모델이 잘못된 결과를 낼 확률이 높다.

 

4. Decision Tree & Random Forest

 

https://www.geeksforgeeks.org/machine-learning/random-forest-algorithm-in-machine-learning/

1) Decision Tree

데이터를 조건문(if-else)으로 쪼개서 예측하는 분류 머신러닝 모델

가장 데이터를 잘 구분할 수 있는 기준을 찾아 순서대로 나눔

2) Random Forest

여러 개의 Decision Tree를 랜덤하게 만들어 그 결과를 투표를 통해 최종 예측하는 앙상블 분류 머신러닝 모델

Random Forest의 결과는 여러 Decision Tree들의 분류 결과들의 최빈값

  • Bootstrap : 전체 데이터 중 일부만 랜덤하게 뽑아 (표본) 학습
  • Feature Randomness : 랜덤하게 추출한 표본 중 랜덤하게 변수를 선택, 랜덤한 순서로 분류
  • Voting : 결과값을 다수결로 투표 (ex. 10개의 Tree 중 8개가 Yes로 분류 ➡️ 해당 데이터는 Yes)

Decision Tree는 한 데이터에 대해 끝까지 분류를 수행하려고 하기 때문에, 노이즈를 학습할 가능성이 높아 과적합(overfitting)이 될 확률이 높다.

하지만 Random Forest는 여러 개의 작은 Decision Tree를 만들고, 각각의 분류 순서도 모두 랜덤하며 분류 결과에 대해 다수결로 투표를 통해 최종 결론을 내기 때문에 이러한 Tree들에서 각각 발생하는 노이즈를 상쇄할 수 있다는 장점이 있다.

Random Forest는 성능과 안정성이 모두 높기 때문에 현업에서도 많이 쓰인다.

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, confusion_matrix
df = pd.read_csv("customer_details.csv")
# 종속변수 값 매핑
df['Subscription Status'] = df['Subscription Status'].map({'Yes':1, 'No':0})
# 머신러닝에 사용할 컬럼/타깃 분리
# ID와 같은 고유값은 머신러닝에 학습시킬 때 빼줘야 한다.
X = df.drop(columns=["Subscription Status", "Customer ID"])
y = df["Subscription Status"]
# One-hot encoding 진행 (범주형 변수를 컬럼으로 쪼개, 이진수처럼 표현함)
X_encoded = pd.get_dummies(X, drop_first=True)
# 머신러닝 모델 적용을 위해 train 데이터와 test 데이터 분리
X_train, X_test, y_train, y_test = train_test_split(X_encoded, y, test_size=0.2, random_state=42)
# Decision Tree 모델에 적용
dt = DecisionTreeClassifier(max_depth=4, random_state=42)
dt.fit(X_train, y_train)
y_pred_dt = dt.predict(X_test)
# 혼동행렬(confusion matrix) 생성
# 예측과 실제 데이터의 차이에 대한 결과표
confusion_matrix(y_test, y_pred_dt)
print(classification_report(y_test, y_pred_dt))
# Random Forest 모델 적용
rf = RandomForestClassifier(n_estimators=200, max_depth=None, random_state=42)
rf.fit(X_train, y_train)
y_pred_rf = rf.predict(X_test)
# 혼동행렬(confusion matrix) 생성
confusion_matrix(y_test, y_pred_rf)
print(classification_report(y_test, y_pred_rf))

Decision Tree 모델 분류 결과
Random Forest 모델 분류 결과

왜 Random Forest가 Decision Tree보다 낮게 나오지?