본문으로 건너뛰기

037 회귀 평가 지표 상세

키워드: MSE, RMSE, MAE, R², 평가 지표

개요

회귀 모델의 성능을 평가하는 다양한 지표가 있습니다. 각 지표는 다른 관점에서 예측 오차를 측정하며, 문제에 따라 적절한 지표를 선택해야 합니다.

실습 환경

  • Python 버전: 3.11 권장
  • 필요 패키지: flaml[automl], scikit-learn, numpy
pip install flaml[automl] scikit-learn numpy matplotlib

예측 오차의 기본

import numpy as np
import pandas as pd

# 037 예시 데이터
y_true = np.array([100, 150, 200, 250, 300])
y_pred = np.array([110, 140, 210, 240, 320])

# 037 오차 계산
errors = y_true - y_pred

print("예측 오차 분석:")
df = pd.DataFrame({
'실제값': y_true,
'예측값': y_pred,
'오차': errors,
'절대오차': np.abs(errors),
'제곱오차': errors ** 2
})
print(df)
print(f"\n오차 합계: {errors.sum()} (양/음이 상쇄됨)")
print(f"절대오차 합계: {np.abs(errors).sum()}")

MSE (Mean Squared Error)

정의

from sklearn.metrics import mean_squared_error

# 037 MSE = (1/n) * Σ(y - ŷ)²
mse_manual = np.mean((y_true - y_pred) ** 2)
mse_sklearn = mean_squared_error(y_true, y_pred)

print("MSE (평균 제곱 오차):")
print(f" 수동 계산: {mse_manual:.2f}")
print(f" sklearn: {mse_sklearn:.2f}")

특징

# 037 MSE의 특징
characteristics = {
'장점': [
'수학적으로 미분 가능 (최적화 용이)',
'큰 오차에 더 큰 패널티 부여',
'이상치에 민감하게 반응'
],
'단점': [
'단위가 제곱됨 (해석 어려움)',
'이상치에 과도하게 민감',
'스케일에 의존적'
]
}

print("MSE 특징:")
for key, values in characteristics.items():
print(f"\n{key}:")
for v in values:
print(f" - {v}")

RMSE (Root Mean Squared Error)

정의

# 037 RMSE = √MSE
rmse = np.sqrt(mse_sklearn)

print("RMSE (평균 제곱근 오차):")
print(f" 값: {rmse:.2f}")
print(f" 해석: 평균적으로 {rmse:.2f}만큼 틀림")

MSE vs RMSE

import matplotlib.pyplot as plt

# 037 다양한 오차 크기에서 비교
errors_range = np.linspace(0, 100, 100)
mse_values = errors_range ** 2
rmse_values = errors_range

fig, axes = plt.subplots(1, 2, figsize=(12, 5))

# 037 MSE
axes[0].plot(errors_range, mse_values, 'b-', linewidth=2)
axes[0].set_xlabel('Error')
axes[0].set_ylabel('MSE')
axes[0].set_title('MSE (quadratic growth)')
axes[0].grid(True, alpha=0.3)

# 037 RMSE
axes[1].plot(errors_range, rmse_values, 'r-', linewidth=2)
axes[1].set_xlabel('Error')
axes[1].set_ylabel('RMSE')
axes[1].set_title('RMSE (linear, same unit as target)')
axes[1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

MAE (Mean Absolute Error)

정의

from sklearn.metrics import mean_absolute_error

# 037 MAE = (1/n) * Σ|y - ŷ|
mae_manual = np.mean(np.abs(y_true - y_pred))
mae_sklearn = mean_absolute_error(y_true, y_pred)

print("MAE (평균 절대 오차):")
print(f" 수동 계산: {mae_manual:.2f}")
print(f" sklearn: {mae_sklearn:.2f}")
print(f" 해석: 평균적으로 {mae_sklearn:.2f}만큼 틀림")

RMSE vs MAE

# 037 이상치 영향 비교
y_true_outlier = np.array([100, 150, 200, 250, 1000]) # 이상치 포함
y_pred_outlier = np.array([110, 140, 210, 240, 300])

rmse_outlier = np.sqrt(mean_squared_error(y_true_outlier, y_pred_outlier))
mae_outlier = mean_absolute_error(y_true_outlier, y_pred_outlier)

print("이상치가 있을 때:")
print(f" RMSE: {rmse_outlier:.2f} (크게 증가)")
print(f" MAE: {mae_outlier:.2f} (상대적으로 안정)")
print("\n→ MAE는 이상치에 더 강건함 (Robust)")

R² (결정 계수)

정의

from sklearn.metrics import r2_score

# 037 R² = 1 - (SS_res / SS_tot)
# 037 SS_res = Σ(y - ŷ)² : 잔차 제곱합
# 037 SS_tot = Σ(y - ȳ)² : 총 제곱합

ss_res = np.sum((y_true - y_pred) ** 2)
ss_tot = np.sum((y_true - y_true.mean()) ** 2)
r2_manual = 1 - (ss_res / ss_tot)
r2_sklearn = r2_score(y_true, y_pred)

print("R² (결정 계수):")
print(f" 수동 계산: {r2_manual:.4f}")
print(f" sklearn: {r2_sklearn:.4f}")
print(f" 해석: 모델이 분산의 {r2_sklearn*100:.1f}%를 설명함")

R² 해석

# 037 R² 해석 가이드
r2_interpretation = {
'R² = 1.0': '완벽한 예측 (실제로는 불가능)',
'R² > 0.9': '매우 좋음',
'0.7 < R² < 0.9': '좋음',
'0.5 < R² < 0.7': '보통',
'0.3 < R² < 0.5': '약함',
'R² < 0.3': '모델 개선 필요',
'R² < 0': '평균 예측보다 나쁨'
}

print("R² 해석 가이드:")
for range_str, interpretation in r2_interpretation.items():
print(f" {range_str}: {interpretation}")

MAPE (Mean Absolute Percentage Error)

정의

# 037 MAPE = (1/n) * Σ|((y - ŷ) / y)| * 100
def mape(y_true, y_pred):
return np.mean(np.abs((y_true - y_pred) / y_true)) * 100

mape_value = mape(y_true, y_pred)

print("MAPE (평균 절대 백분율 오차):")
print(f" 값: {mape_value:.2f}%")
print(f" 해석: 평균적으로 {mape_value:.2f}% 틀림")

MAPE 주의사항

# 037 MAPE의 문제: 실제값이 0에 가까울 때
y_true_zero = np.array([0.1, 0.5, 1.0, 5.0, 10.0])
y_pred_zero = np.array([0.2, 0.4, 1.2, 4.8, 10.5])

mape_zero = mape(y_true_zero, y_pred_zero)
print(f"\n작은 실제값이 있을 때 MAPE: {mape_zero:.2f}%")
print("→ 실제값이 0이면 MAPE는 무한대!")

지표 비교 함수

def evaluate_regression(y_true, y_pred, name="Model"):
"""회귀 평가 지표 종합"""
from sklearn.metrics import (
mean_squared_error, mean_absolute_error, r2_score
)

mse = mean_squared_error(y_true, y_pred)
rmse = np.sqrt(mse)
mae = mean_absolute_error(y_true, y_pred)
r2 = r2_score(y_true, y_pred)

# MAPE (0 값 방지)
mask = y_true != 0
if mask.sum() > 0:
mape_val = np.mean(np.abs((y_true[mask] - y_pred[mask]) / y_true[mask])) * 100
else:
mape_val = np.nan

print(f"=== {name} 평가 결과 ===")
print(f"MSE: {mse:.4f}")
print(f"RMSE: {rmse:.4f}")
print(f"MAE: {mae:.4f}")
print(f"R²: {r2:.4f}")
print(f"MAPE: {mape_val:.2f}%")

return {'mse': mse, 'rmse': rmse, 'mae': mae, 'r2': r2, 'mape': mape_val}

# 037 사용 예
results = evaluate_regression(y_true, y_pred, "예시 모델")

FLAML에서 회귀 metric 설정

from flaml import AutoML
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split

# 037 데이터 준비
data = fetch_california_housing()
X_train, X_test, y_train, y_test = train_test_split(
data.data, data.target, test_size=0.2, random_state=42
)

# 037 다양한 metric으로 학습
metrics = ['r2', 'mse', 'mae']

for metric in metrics:
automl = AutoML()
automl.fit(
X_train, y_train,
task="regression",
time_budget=30,
metric=metric,
verbose=0
)

y_pred = automl.predict(X_test)
r2 = r2_score(y_test, y_pred)

print(f"metric='{metric}': R²={r2:.4f}, 모델={automl.best_estimator}")

지표 선택 가이드

selection_guide = {
'상황': ['일반적인 경우', '이상치 많음', '비율이 중요', '모델 설명력 평가', '비즈니스 보고'],
'권장 지표': ['RMSE', 'MAE', 'MAPE', 'R²', 'MAE 또는 MAPE'],
'이유': [
'MSE 기반, 큰 오차 패널티',
'이상치에 강건',
'상대적 오차 중요',
'분산 설명 비율',
'해석하기 쉬움'
]
}

print("\n지표 선택 가이드:")
print(pd.DataFrame(selection_guide).to_string(index=False))

정리

지표수식특징단위
MSE(1/n)Σ(y-ŷ)²큰 오차 패널티, 미분 가능제곱
RMSE√MSE원래 단위, 해석 용이원래
MAE(1/n)Σ|y-ŷ|이상치에 강건원래
1-(SS_res/SS_tot)0~1 스케일, 설명력없음
MAPE(1/n)Σ|오차/y|×100백분율, 비교 용이%

다음 글 예고

다음 글에서는 캘리포니아 주택 가격 예측 프로젝트를 진행합니다. 실제 부동산 데이터를 활용한 회귀 프로젝트의 전체 과정을 다룹니다.


FLAML AutoML 마스터 시리즈 #037