머신러닝 - 분류 모델의 평가지표(Classification)

|

개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.


분류 모델의 평가지표(Classification)이 왜 중요한가?

모델 성능을 잘못 해석하면 실제로는 못 쓰는 모델을 선택할 수 있고, 비즈니스 목표(예: 불량 최소화/조기경보/추천 정확성)와 어긋난 판단을 내릴 수 있다.

핵심: “문제의 성격(분류/회귀/랭킹/불균형 등)과 비즈니스 목표”에 맞는 지표를 고르는 것이 성능 수치 그 자체보다 중요

  • TP(진양성): 실제 양성을 양성으로 맞춤
  • TN(진음성): 실제 음성을 음성으로 맞춤
  • FP(위양성, Type I 오류): 실제 음성인데 양성으로 잘못 예측
  • FN(위음성, Type II 오류): 실제 양성인데 음성으로 잘못 예측

정확도(Accuracy)

실제와 맞게 예측한 확률

[{Accuracy}=\frac{TP+TN}{TP+TN+FP+FN}]

정밀도(Precision)=예측력

예측을 참이라고 했는데, 실제로도 참인 확률

  • 해석: “양성이라 예측한 것 중 실제로 맞춘 비율”

[{Precision}=\frac{TP}{TP+FP}]

  • 🕐 사용 시기: False Positive(오탐) 를 특히 줄여야 할 때
    (예: 스팸 분류에서 정상메일을 스팸으로 막으면 곤란)

재현율(Recall, Sensitivity)=민감도

실제로 참인 경우, 예측도 참으로 한 확률

  • 해석: “실제 양성 중에서 얼마나 잘 찾아냈는가”

[{Recall}=\frac{TP}{TP+FN}]

  • 🕐 사용 시기: False Negative(미탐) 를 특히 줄여야 할 때
    (예: 질병 진단, 사기 탐지의 조기경보)

특이도(Specificity)

실제로 거짓인데, 예측도 거짓으로 한 확률

  • 해석: “실제 음성을 얼마나 잘 골라내는가”

[{Specificity}=\frac{TN}{TN+FP}]

F1 점수(F1 Score)

정밀도–재현율의 조화평균

[F1=2\cdot \frac{\text{Precision}\cdot \text{Recall}}{\text{Precision}+\text{Recall}}]

  • 🕐 사용 시기: 두 지표 모두 중요하고, 불균형이 있는 경우

F-베타(F-β) 점수

[Fβ=(1+\beta^2)\cdot \frac{\text{Precision}\cdot \text{Recall}}{\beta^2\cdot \text{Precision}+\text{Recall}}]

  • β>1: 재현율에 더 큰 가중치
  • β<1: 정밀도에 더 큰 가중치
  • β=1: F1과 동일

머신러닝 - 로지스틱 회귀모델(Logistic Regression)

|

개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.


로지스틱 회귀모델(Logistic Regression)란?

문제를 해결하기 위한 대표적인 지도학습 알고리즘 > 분류 알고리즘이다.

특징

  • 이진 분류: 두 개의 클래스를 구분 (예: 스팸/정상 메일)
  • 확률 예측: 0과 1 사이의 확률값으로 결과 출력
  • 시그모이드 함수: S자 곡선 형태의 활성화 함수 사용
  • 선형 결정 경계: 데이터를 선형적으로 분리

라이브러리 불러오기

import numpy as np # 넘파이
import pandas as pd #pandas

from sklearn.model_selection import train_test_split  #데이터 분리
from sklearn.linear_model import LogisticRegression  #LogisticRegression 로지스틱 회귀모델
from sklearn.preprocessing import StandardScaler #StandardScaler 데이터 정규화
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report #범주형에 따른 새로운 매트릭

import matplotlib.pyplot as plt #시각화
import seaborn as sns#시각화

데이터 불러오기

train = pd.read_csv('https://ds-lecture-data.s3.ap-northeast-2.amazonaws.com/titanic/train.csv')
test = pd.read_csv('https://ds-lecture-data.s3.ap-northeast-2.amazonaws.com/titanic/test.csv')

target = 'Survived'

# difference > 필요없는 컬럼들 빼줌 / 따라서 feature안에는 필요한 애들만 들어가있는 것!
features = train.columns.difference(['Survived', 'PassengerId', 'Name', 'Ticket', 'Cabin']) 


X = train[features]
y = train[target]

# 교안이 잘 만들어짐! > X!
# 스케일링은 X만 스케일하기 때문에 대부분 X랑 y로 분할 한다음에 X만 스케일링 함
X

데이터 전처리 - 원 핫 인코딩

from sklearn.preprocessing import OneHotEncoder

# get dummies를 쓰거나 scikit-learn 를 쓰거나 둘 중 하나를 선택
X = pd.get_dummies(X) #, drop_first=True)
X

데이터 분할

# 위에서 만든 교안 X은 0,1로 바꿔진 상태인데 80% train, 20% test로 분리하겠다는 뜻 !
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2)
X_train

결측값 처리 > sklearn

from sklearn.impute import SimpleImputer

# 훈련된 train 데이터에 결측값이 있을 수 있음! 
# > pandas에서 처리할지 sklearn에서 처리할지는 알아서 선택! 
# strategy='mean': 결측값을 자동으로 찾아 평균값을 넣어주는 것 > 다 수치형이나까 평균값을 넣어도 됨 
imputer = SimpleImputer(strategy='mean')
X_train_imputed = imputer.fit_transform(X_train)
X_val_imputed = imputer.transform(X_val)

특성 스케일링

from sklearn.preprocessing import StandardScaler

# 특성이란 것이 feature > 컬럼값이라는 뜻인데 
# 표준편차에 집어넣어서 다 0+-a로 바꾸게 됨 
# 이 특성 스케일링을 지나고 나서 남는 최종 결과물은 0.~ 1.~ 이런식으로 표준화된 값이 나옴
# 기존 데이터들이 다 바뀜 > 컴퓨터는 이게 판단하기가 더 쉬움! 
# 즉, 각기 다른 수치들의 단위를 맞춰주는 것이 스케일링! 
scaler = StandardScaler()

# 스케일링을 한 데이터로 학습 시켰으니까 모델은 스케일링한 데이터로 학습이 되었겠죠? 
# 그렇다면 스케일링을 안한 데이터로 평가를 하면 정확도가 떨어지기 때문에 
# 테스트와 훈련 모두 스케일링 처리를 한다~ 고 이해하시면 되요!
# 스케일링 했으면 train과 test 둘다 해줘야함 
# 둘다 똑같이 작업한 다음에 비교해줘야함
X_train_scaled = scaler.fit_transform(X_train_imputed)
X_val_scaled = scaler.transform(X_val_imputed)

모델학습

from sklearn.linear_model import LogisticRegression

# f(X_train_scaled) = y_train
# f(X_train_scaled) = y^ 
model = LogisticRegression(random_state=42)
model.fit(X_train_scaled, y_train)

결과 예측

from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score

# y_val: 실제 정답 / y_pred: 예측 값 > 이 둘을 가지고 정확도를 측정해야함! 
# y^ 과 y_val 비교 
y_pred = model.predict(X_val_scaled)

모델 평가

from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score

accuracy = accuracy_score(y_val, y_pred)  # 정확도
precision = precision_score(y_val, y_pred)  # 정밀도
recall = recall_score(y_val, y_pred)  # 재현율 
f1 = f1_score(y_val, y_pred)

print(f"정확도 :{accuracy:.2f}")
print(f"정밀도 :{precision:.2f}")
print(f"정확도 :{recall:.2f}")
print(f"f1 score :{f1:.2f}")
# 정확도 :0.77
# 정밀도 :0.67
# 정확도 :0.74
# f1 score :0.71

지도학습과 비지도 학습

  1. 지도 학습: y(결과값)가 주어진 경우
    • y가 수치형인 경우: 회귀모델
    • y가 범주형인 경우: 분류모델(로지스틱 회귀모델..)
    • 이 외에도 KNN, 나이브베이즈, SVM, 결정트리, 앙살블(그래디언트 부스트, 랜덤포레스트, 부스팅..), 스태킹..
  2. 비지도 학습: y(결과값)가 주어지지 않은 경우
    • 군집 분석
    • K-means, DBScan, 덴드로그램

원핫 인코딩(One-Hot Encoding)

표현하고 싶은 단어의 인덱스에 1의 값을 부여하고, 다른 인덱스에는 0을 부여하는 단어의 벡터 표현 방식을 말하며, 이렇게 표현된 벡터를 원-핫 벡터(One-Hot vector)라고 한다.

  • 원핫인코딩 하기에 적합한 경우
    • 데이터가 범주형이어야 함
    • 범주형이더라도 숫자형이면 꼭 할 필요 없고, 문자형일 경우 하면 좋음!

ex) 타이타닉 데이터셋에서

  • 적합한 경우 : sex, embarked
  • 부적합한 경우 : pclass & name
    • pclass는 범주형이기는 하지만 이미 숫자이기 때문
    • 즉, 변경 여부가 모델학습에 큰 영향을 미치지 않음
pd.get_dummies(df, columns=['sex','embarked'], dtype='int')

# pandas 사용
pd.get_dummies(df, columns=['범주형_컬럼'])

# scikit-learn 사용
from sklearn.preprocessing import OneHotEncoder
encoder = OneHotEncoder()
encoded = encoder.fit_transform(data)

레이블 인코딩

그 외 대표적인 인코딩 기법에는 레이블 인코딩이 있으며 이는 각 범주에 고유한 정수를 할당하여 숫자로 변환하는 방식을 말한다.

(예를들어, C : 0, Q : 1, S : 2) 이런식으로 각 값마나 숫자를 부여함!

info = {C : 0, Q : 1, S : 2}
df['embarked'].map(info)

머신러닝 - 교차검증(k-fold cross_validation)

|

개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.


교차검증(k-fold cross_validation)란?

전체 데이터셋을 k개의 fold로 나누어 1개의 fold를 test data로, 나머지 (k-1)개의 foldfmf train data로 분할하는 과정을 반복함으로써 train, test data를 교차 변경하는 방법론

즉, 학습데이터 셋과 검증 데이터 셋을 점진적으로 변경하면서 마지막 k번째까지 학습, 검증을 수행함!

진행순서

  1. 데이터 분할(설정할 수 있는 하이퍼파라미터)
  2. 반복학습
  3. 성능측정: 각 반복에서 검증 성능 측정
  4. 각 점수를 평균, 표준편차 계산

이 작업을 왜 하는걸까?

  • 과적합을 줄일 수 있음
  • 측면 반복학습이다 보니 성능이 안정적일 수 있고,
  • 기존 하나의 데이터를 뜯어볼수 있어 데이터 활용이 극대화 됨

구현해보기

# k-fold 라이브러리 불러오기
from sklearn.model_selection import KFold, cross_val_score

df = pd.read_csv('https://ds-lecture-data.s3.ap-northeast-2.amazonaws.com/house-prices/house_prices_train.csv')

X= df[['GrLivArea', 'LotArea']]
y = df['SalePrice']

# 선형회귀모델 정의
simple_model = LinearRegression() 
# 모델 훈련
simple_model.fit(X,y)

# n_splits > 5개로 나누고, 섞어줌 (그래서 실행마다 array값이 조금씩 바뀜!)
kf = KFold(n_splits=5, shuffle=True, random_state=42)

# 훈련 끝난 데이터, 데이터, y값, scoring=평균으로 계산할지? 표준편차로 계산할지? ,cv=내가 정의한 kfold 정보를 넣으줌 
# 사이킷런 규칙으로 MSE는 값을 음수로 반환
# 사이킷런은 모든 평가 점수를 클수록 좋은 점수로 규칙을 맞춰놓음 > 근데 MSE는 작을수록 좋으니 규칙에 맞지않음
MSE_score = cross_val_score(simple_model, X, y, scoring='neg_mean_squared_error', cv=kf)
MSE_score
# array([-3.38953122e+09, -2.77111324e+09, -4.35654599e+09, -2.90526053e+09, -2.47771029e+09])

# 그래서 임의로 다시 우리가 그 값에 -를 붙여 양수로 반환시킴 > 이게 진짜 우리가 보고싶은 MSE 값임!
-MSE_score.mean()
# np.float64(3180032254.0430913)

머신러닝 - 모델 정규화(Ridge, Lasso, Elastic Net)

|

개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.


정규화(Regularization)란?

머신러닝/딥러닝 학습에서의 정규화란 모델의 과적합을 막기위해, 모델 성능의 일반화를 위해 수행되는 것을 의미함

모델이 너무 복잡해지거나, 파라미터의 개수가 너무 많아지는 것을 막기 위해 정규화를 사용함. 이 대표적인 종류로 L1, L2 정규화가 있다.

위 그림과 같이 정규화는 모델 복잡도, 정확도 면에서 최적의 해를 찾는 것이 정규화의 수행 의의이다.

릿지(Ridge) Regression > L2 규제

  • 릿지 회귀는 선형 회귀를 개선한 선형 모델
  • 릿지 회귀는 선형 회귀와 비슷하지만, 가중치의 절대값을 최대한 작게 만든다는 것이 다름
  • 이러한 방법은 각각의 특성(feature)이 출력 값에 주는 영향을 최소한으로 만들도록 규제(regularization)를 거는 것
  • 규제를 사용하면 다중공선성(multicollinearity) 문제를 방지하기 때문에 모델의 과대적합을 막을 수 있게 됨
  • 다중공선성 문제는 두 특성이 일치에 가까울 정도로 관련성(상관관계)이 높을 경우 발생
  • 릿지 회귀는 다음과 같은 함수를 최소화하는 파라미터 $w$를 찾음

[\text{RidgeMSE} = \frac{1}{N} \sum_{i=1}^{N}(y_i - \hat{y}i)^2 + \alpha \sum{i=1}^{p} w_i^2]

  • $\alpha$ : 사용자가 지정하는 매개변수
  • $\alpha$가 크면 규제의 효과가 커지고, $\alpha$가 작으면 규제의 효과가 작아짐

라이브러리 불러오기

from sklearn.linear_model import LinearRegression, Ridge, Lasso  # 선형회귀, 릿지, 랏쏘
from sklearn.model_selection import train_test_split  # 데이터셋 분리
from sklearn.metrics import mean_squared_error, r2_score  # matrixs MSE, r^2
import matplotlib.pyplot as plt  # 시각화 
import numpy as np
import pandas as pd

데이터 불러오기

df = pd.read_csv('https://ds-lecture-data.s3.ap-northeast-2.amazonaws.com/house-prices/house_prices_train.csv')

X = df[['GrLivArea', 'LotArea']]
y = df['SalePrice']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

모델 정의

# 𝛼 가 크면 규제의 효과가 커지고,  𝛼 가 작으면 규제의 효과가 작아짐
ridge_model = Ridge(alpha=0.1)

ridge_model.fit(X_train, y_train)

모델 예측

pred_ridge = ridge_model.predict(X_test)  # X_test에 따른 predict 값이 나옴 

MSE_ridge = mean_squared_error(y_test, pred_ridge)
MSE_ridge
# 3389531220.090343

릿지(Lasso) Regression > L1 규제

  • 선형 회귀에 규제를 적용한 또 다른 모델로 라쏘 회귀가 있음
  • 라쏘 회귀는 릿지 회귀와 비슷하게 가중치를 0에 가깝게 만들지만, 조금 다른 방식을 사용
  • 라쏘 회귀에서는 다음과 같은 함수를 최소화하는 파라미터 $w$를 찾음
[\text{LassoMSE} = \frac{1}{N} \sum_{i=1}^{N}(y_i - \hat{y}i)^2 + \alpha \sum{i=1}^{p} w_i ]
  • 라쏘 회귀도 매개변수인 $\alpha$ 값을 통해 규제의 강도 조절 가능

구현해보기

lasso_model = Lasso(alpha=0.3)
lasso_model.fit(X_train, y_train)

pred_lasso = lasso_model.predict(X_test)

MSE_lasso = mean_squared_error(y_test, pred_lasso)
MSE_lasso
# 3389531228.8286858

Elastic-Net(Ridge+Lasso)

  • 신축망은 릿지 회귀와 라쏘 회귀, 두 모델의 모든 규제를 사용하는 선형 모델
  • 두 모델의 장점을 모두 갖고 있기 때문에 좋은 성능을 보임
  • 데이터 특성이 많거나 서로 상관 관계가 높은 특성이 존재할 때 위의 두 모델보다 좋은 성능을 보여줌
  • 신축망은 다음과 같은 함수를 최소화하는 파라미터 $w$를 찾음
[\text{ElasticMSE} = \frac{1}{N} \sum_{i=1}^{N}(y_i - \hat{y}i) + \alpha \rho \sum{i=1}^{p} w_i + \alpha(1-\rho) \sum_{i=1}^{p} w_i^2]
  • $\alpha$ : 규제의 강도를 조절하는 매개변수
  • $\rho$ : 라쏘 규제와 릿지 규제 사이의 가중치를 조절하는 매개변수

구현해보기

from sklearn.linear_model import ElasticNet
# 엘라스틱 모델 정의
elastic_model = ElasticNet(alpha=0.3, l1_ratio=0.5)
# 엘라스틱 모델 훈련
elastic_model.fit(X_train, y_train)

# 예측
pred_elastic = elastic_model.predict(X_test)

# MSE 
MSE_elastic = mean_squared_error(y_test, pred_elastic)
MSE_elastic
# 3389531933.0839124

머신러닝 - Bias(편향)와 Variance(분산)?

|

개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.


Bias, Variance

  • Bias: 편향, 모델이 예측한 값과 실제 정답 간의 오차를 의미
  • Variance: 분산, 모델이 예측한 값이 서로 얼마나 퍼져있나를 의미하는 수치

Bias

탁구공, 농구공 등의 데이터가 들어왔을 때, 이것을 공으로 분류해야하지만 동그라미로 분류하게 되면 실제 정답간의 차이가 생기게 된다. 이 차이의 정도를 bias라고 한다.

Variance

  • 모델의 variance가 낮다 = 모델의 복잡도가 낮다
  • 모델의 variance가 높다 = 모델의 복잡도가 높다

동그란 것을 공으로 분류한다고 생각해보자. 이때는 동그랗다는 특징만 가지고 있기 때문에 탁구공, 농구공의 문양과 같은 국소적인 특징에는 집착하지 않아도 된다. 따라서 탁구공, 농구공에 대해 모델이 비슷한 값을 출력할 것이다. 즉, variance가 낮게 나올 것이다.

즉, 우리가 ‘공’이라고 분류하고 싶은 데이터에 대해서 모델이 출력하는 값 또한 ‘공’으로 비슷할 것

그러나 동그랗고, 맨들거리고 등등과 같은 다양한 특징을 공을 분류하기 위해 사용한다면 탁구공, 농구공에 대해 모델의 값이 많이 달라질 것이다. 농구공은 겉이 꺼끌거리지만 탁구공은 부드럽기 때문에 같은 공임에도 불구하고 예측값이 다르게 나올 것 이다. 즉. variance가 높게 나올 것이다.

데이터를 ‘공’으로 분류하고 싶지만 추가적인 특징들이 모델을 다른 공으로 분류하도록 할 수 있음

따라서 같은 공을 분류함에도 어떤 특징을 사용하느냐에 따라 예측값의 퍼져있는 정도, 데이터셋의 예민한 정도가 다 다르다. 이러한 것을 측정하는 데에 사용하는 것이 variance이다.

위 그림은 train, test 데이터에 대한 결과를 bias, variance 관점에서 해석한 그림이다. 이는 MSE 수식을 통해 바라볼 수 있다.

  • 가운데 주황색 동그라미 영역은 target으로, 정답&참값을 의미함
  • 초록색 점들은 모델이 예측한 값을 의미함
  1. Low Bias & Low Variance (좌상단): 실제 정답과 예측 값들의 차이가 적고, 예측값들의 variance도 낮아서 loss가 낮은 모델이다. 모든 데이터셋에서 이러한 경향을 보인다면 학습이 잘 되었다고 볼 수 있다.
  2. Low Bias & High Variance (우상단): 예측한 값을 평균한 값은 정답과 비슷한데, 예측값들의 variance가 높아 loss가 높은 모델아다.
  3. High Bias & Low Variance (좌하단): 예측값들의 variance는 낮지만 실제 정답과의 차이가 큰 경우로 학습이 잘 안 된 경우로 볼 수 있다.
  4. High Bias & High Variance (우하단): Bias와 Variance 둘 다 높아 학습이 잘 안 된 경우이다.