bonggyulim 님의 블로그
ML - 모델 학습 및 평가 본문
전처리가 끝났다면 이제 본격적으로 머신러닝 모델을 학습시키고 성능을 평가할 수 있다. 실제 머신러닝 프로젝트에서는 모델 하나만 사용하는 것이 아니라, 여러 모델을 비교해보고 데이터에 더 잘 맞는 모델을 선택하는 과정이 중요하다.
이번 글에서는 대표적인 회귀 모델과 분류 모델의 기본 사용법을 정리한다.
- 회귀 예제: tips 데이터셋
- 분류 예제: iris 데이터셋
1. 회귀 모델 학습 파트
회귀는 연속적인 숫자 값을 예측하는 문제이다.
예를 들어 집값, 매출, 온도, 점수처럼 숫자로 표현되는 값을 예측할 때 회귀 모델을 사용한다.
이번 예제에서는 tips 데이터셋을 사용해서 **팁 금액(tip)**을 예측해본다.
1.0. 데이터 준비
tips = sns.load_dataset("tips").copy()
# 결측치 / 중복 제거
tips = tips.dropna().drop_duplicates()
# 먼저 설명력이 높을 가능성이 큰 컬럼만 사용
selected_features_reg = ["total_bill", "size", "smoker", "time"]
X_reg = tips[selected_features_reg]
y_reg = tips["tip"]
categorical_cols_reg = X_reg.select_dtypes(include=["object", "category"]).columns.tolist()
numeric_cols_reg = X_reg.select_dtypes(include=["int64", "float64"]).columns.tolist()
preprocessor_reg = ColumnTransformer(
transformers=[
("num", StandardScaler(), numeric_cols_reg),
("cat", OneHotEncoder(handle_unknown="ignore"), categorical_cols_reg)
]
)
X_train_reg, X_test_reg, y_train_reg, y_test_reg = train_test_split(
X_reg, y_reg, test_size=0.2, random_state=42
)
tips 데이터셋에는 총 결제 금액, 성별, 흡연 여부, 요일, 시간대, 인원 수 등의 정보가 들어 있다.
이 중에서 tip을 타깃으로 두고 나머지 컬럼을 입력값으로 사용한다.
여기서는 수치형 컬럼에는 StandardScaler를 적용하고, 범주형 컬럼에는 OneHotEncoder를 적용한다.
1.1. LinearRegression
LinearRegression은 가장 기본적인 선형 회귀 모델이다.
입력 변수와 타깃 사이의 선형 관계를 바탕으로 예측한다.
해석이 쉽고 빠르기 때문에 회귀 문제의 첫 출발점으로 많이 사용한다.
lr_reg_model = Pipeline([
("preprocessor", preprocessor_reg),
("model", LinearRegression())
])
lr_reg_model.fit(X_train_reg, y_train_reg)
lr_reg_pred = lr_reg_model.predict(X_test_reg)
print(lr_reg_pred[:5])
선형 관계가 어느 정도 잘 맞는 데이터에서는 좋은 기준 모델이 될 수 있다.
다만 관계가 복잡하거나 비선형 패턴이 강하면 성능이 제한될 수 있다.
1.2. Ridge
Ridge는 선형 회귀에 L2 정규화를 추가한 모델이다.
변수가 많거나 다중공선성이 있을 때 계수가 지나치게 커지는 것을 완화하는 데 도움이 된다.
ridge_reg_model = Pipeline([
("preprocessor", preprocessor_reg),
("model", Ridge(alpha=1.0))
])
ridge_reg_model.fit(X_train_reg, y_train_reg)
ridge_reg_pred = ridge_reg_model.predict(X_test_reg)
선형 회귀와 비슷하게 사용할 수 있지만, 과적합을 조금 더 안정적으로 제어할 수 있다는 장점이 있다.
1.3. Lasso
Lasso는 선형 회귀에 L1 정규화를 추가한 모델이다.
불필요한 변수의 계수를 0으로 만들 수 있어서 변수 선택 효과가 나타날 수 있다.
lasso_reg_model = Pipeline([
("preprocessor", preprocessor_reg),
("model", Lasso(alpha=0.1))
])
lasso_reg_model.fit(X_train_reg, y_train_reg)
lasso_reg_pred = lasso_reg_model.predict(X_test_reg)
변수가 많고 어떤 변수가 중요한지 함께 보고 싶을 때 자주 사용한다.
다만 alpha 값에 따라 성능 차이가 크게 날 수 있으므로 튜닝이 중요하다.
선형 회귀 모델은 입력 변수가 많아지거나 서로 비슷한 정보를 가진 변수가 함께 들어오면, 특정 계수가 지나치게 커지면서 훈련 데이터에만 잘 맞는 방향으로 학습될 수 있다. 이런 문제를 완화하기 위해 사용하는 방법이 정규화(Regularization) 이다.
정규화는 모델의 계수가 너무 커지지 않도록 패널티를 주는 방식이다.
즉, 단순히 훈련 데이터에만 맞추는 것이 아니라 조금 더 일반화된 예측을 하도록 유도하는 역할을 한다.
- L1 정규화(Lasso): 불필요한 변수의 계수를 0으로 만들 수 있음
- L2 정규화(Ridge): 계수 크기를 전반적으로 줄여 과적합을 완화함
1.4. DecisionTreeRegressor
DecisionTreeRegressor는 데이터를 규칙 기반으로 계속 나누면서 예측하는 모델이다.
비선형 관계를 잘 다룰 수 있고, 구조를 이해하기도 비교적 쉽다.
tree_reg_model = Pipeline([
("preprocessor", preprocessor_reg),
("model", DecisionTreeRegressor(random_state=42))
])
tree_reg_model.fit(X_train_reg, y_train_reg)
tree_reg_pred = tree_reg_model.predict(X_test_reg)
데이터의 복잡한 패턴을 잡아낼 수 있지만, 깊이가 너무 깊어지면 과적합되기 쉽다.
1.5. RandomForestRegressor
RandomForestRegressor는 여러 개의 결정트리를 만들어 그 결과를 평균내는 앙상블 모델이다.
단일 트리보다 일반화 성능이 더 좋은 경우가 많고, 실무에서도 자주 사용한다.
rf_reg_model = Pipeline([
("preprocessor", preprocessor_reg),
("model", RandomForestRegressor(random_state=42))
])
rf_reg_model.fit(X_train_reg, y_train_reg)
rf_reg_pred = rf_reg_model.predict(X_test_reg)
기본 성능이 안정적인 편이라 회귀 문제에서 자주 비교 대상으로 올라오는 모델이다.
1.6. KNeighborsRegressor
가까운 이웃들의 값을 참고해서 예측하는 모델이다.
단순하지만 데이터 스케일에 민감하고, 데이터 양이 많아지면 예측 속도가 느려질 수 있다.
knn_reg_model = Pipeline([
("preprocessor", preprocessor_reg),
("model", KNeighborsRegressor(n_neighbors=5))
])
knn_reg_model.fit(X_train_reg, y_train_reg)
knn_reg_pred = knn_reg_model.predict(X_test_reg)
1.7. SVR
서포트 벡터 머신을 회귀에 적용한 모델이다.
복잡한 관계를 잘 잡을 수 있지만, 데이터가 많아질수록 학습 비용이 커질 수 있다.
svr_reg_model = Pipeline([
("preprocessor", preprocessor_reg),
("model", SVR())
])
svr_reg_model.fit(X_train_reg, y_train_reg)
svr_reg_pred = svr_reg_model.predict(X_test_reg)
2. 분류 모델 학습 파트
분류는 정답이 숫자 연속값이 아니라 범주(label) 인 문제이다.
예를 들어 이메일이 스팸인지 아닌지, 꽃의 품종이 무엇인지, 고객이 이탈할지 말지 등을 예측할 때 분류 모델을 사용한다.
이번 예제에서는 iris 데이터셋을 사용해서 꽃의 품종을 예측해본다.
2.0. 데이터 준비
iris = load_iris(as_frame=True)
df_iris = iris.frame
X_clf = df_iris.drop("target", axis=1)
y_clf = df_iris["target"]
X_train_clf, X_test_clf, y_train_clf, y_test_clf = train_test_split(
X_clf,
y_clf,
test_size=0.2,
random_state=42,
stratify=y_clf
)
iris 데이터셋은 이미 수치형 변수로 정리되어 있기 때문에 비교적 간단하게 사용할 수 있다.
분류 문제에서는 stratify=y를 넣어서 클래스 비율이 학습용과 테스트용에 비슷하게 유지되도록 하는 경우가 많다.
2.1. LogisticRegression
LogisticRegression은 이름에 회귀가 들어가지만 대표적인 분류 모델이다.
기본이 되는 선형 분류 모델로, 빠르고 해석도 비교적 쉬운 편이다.
log_clf_model = Pipeline([
("scaler", StandardScaler()),
("model", LogisticRegression(max_iter=1000))
])
log_clf_model.fit(X_train_clf, y_train_clf)
log_clf_pred = log_clf_model.predict(X_test_clf)
선형적으로 구분이 어느 정도 가능한 문제에서 좋은 출발점이 된다.
2.2. KNeighborsClassifier
KNeighborsClassifier는 가까운 샘플들의 다수결로 클래스를 예측하는 모델이다.
직관적이고 이해하기 쉽지만, 거리 기반이라 스케일링이 중요하다.
knn_clf_model = Pipeline([
("scaler", StandardScaler()),
("model", KNeighborsClassifier(n_neighbors=5))
])
knn_clf_model.fit(X_train_clf, y_train_clf)
knn_clf_pred = knn_clf_model.predict(X_test_clf)
데이터 구조가 비교적 단순할 때 좋은 성능을 내는 경우가 많다.
2.3. DecisionTreeClassifier
DecisionTreeClassifier는 질문을 반복하면서 데이터를 나누는 방식으로 클래스를 분류한다.
비선형 패턴을 반영할 수 있고, 규칙 기반이라 해석도 쉬운 편이다.
tree_clf_model = Pipeline([
("model", DecisionTreeClassifier(random_state=42))
])
tree_clf_model.fit(X_train_clf, y_train_clf)
tree_clf_pred = tree_clf_model.predict(X_test_clf)
2.4. RandomForestClassifier
RandomForestClassifier는 여러 개의 결정트리를 조합한 앙상블 분류 모델이다.
기본 성능이 안정적이고 실무에서도 자주 사용된다.
rf_clf_model = Pipeline([
("model", DecisionTreeClassifier(random_state=42))
])
rf_clf_model.fit(X_train_clf, y_train_clf)
rf_clf_model = tree_clf_model.predict(X_test_clf)
단일 트리보다 과적합이 덜하고, 중요한 변수를 함께 확인할 수 있다는 장점이 있다.
2.5. SVC
서포트 벡터 머신 기반 분류 모델이다.
결정 경계를 잘 찾는 편이고 성능이 좋은 경우가 많지만, 데이터가 커질수록 계산량이 증가할 수 있다.
svc_clf_model = Pipeline([
("scaler", StandardScaler()),
("model", SVC())
])
svc_clf_model.fit(X_train_clf, y_train_clf)
svc_clf_pred = svc_clf_model.predict(X_test_clf)
2.6. GradientBoostingClassifier
이전 모델의 오차를 보완해가며 순차적으로 학습하는 부스팅 계열 모델이다.
성능이 잘 나오는 경우가 많지만, 하이퍼파라미터에 민감할 수 있다.
gb_clf_model = Pipeline([
("model", GradientBoostingClassifier(random_state=42))
])
gb_clf_model.fit(X_train_clf, y_train_clf)
gb_clf_pred = gb_clf_model.predict(X_test_clf)
3. 교차검증
학습 데이터를 한 번만 나눠서 성능을 평가하면, 우연히 잘 나왔거나 우연히 낮게 나올 수 있다.
즉, train/test split 한 번만으로는 모델의 성능을 안정적으로 판단하기 어려울 수 있다.
이럴 때 사용하는 것이 교차검증(Cross Validation) 이다.
교차검증은 데이터를 여러 번 나눠서 반복적으로 학습하고 평가한 뒤 평균 성능을 확인하는 방식이다.
3.1. cross_val_scor
# 회귀 모델 교차검증
lr_cv_pipe = Pipeline([
("preprocessor", preprocessor_reg),
("model", LinearRegression())
])
cv_scores_reg = cross_val_score(
lr_cv_pipe,
X_reg,
y_reg,
cv=5,
scoring="r2"
)
print("회귀 교차검증 R2:", cv_scores_reg)
print("회귀 평균 R2:", cv_scores_reg.mean())
3.2. KFold와 StratifiedKFold
- KFold는 데이터를 단순히 K개로 나눈다.
# 회귀 모델 교차검증
lr_cv_pipe = Pipeline([
("preprocessor", preprocessor_reg),
("model", LinearRegression())
])
cv_scores_reg = cross_val_score(
lr_cv_pipe,
X_reg,
y_reg,
cv=5,
scoring="r2"
)
print("회귀 교차검증 R2:", cv_scores_reg)
print("회귀 평균 R2:", cv_scores_reg.mean())
- StratifiedKFold는 클래스 비율을 유지하면서 나눈다.
분류 문제에서는 클래스 비율이 중요하기 때문에 StratifiedKFold가 자주 사용된다.
# 분류 모델 교차검증
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
rf_cv_clf_pipe = Pipeline([
("model", RandomForestClassifier(random_state=42))
])
cv_scores_clf = cross_val_score(
rf_cv_clf_pipe,
X_clf,
y_clf,
cv=skf,
scoring="accuracy"
)
print("분류 교차검증 Accuracy:", cv_scores_clf)
print("분류 평균 Accuracy:", cv_scores_clf.mean())
4. 하이퍼파라미터 튜닝
모델에는 사람이 직접 설정해야 하는 값들이 있다.
예를 들어 트리의 최대 깊이, 랜덤포레스트의 트리 개수, KNN의 이웃 수 같은 값이 여기에 해당한다.
이런 값을 하이퍼파라미터라고 한다.
반면, 모델이 학습 과정에서 스스로 찾는 값은 학습 파라미터라고 볼 수 있다.
예를 들어 선형 회귀의 계수 값은 학습 파라미터이다.
4.1 GridSearchCV
GridSearchCV는 미리 정한 하이퍼파라미터 조합을 전부 탐색하는 방식이다.
후보 수가 많지 않을 때는 체계적으로 확인할 수 있다는 장점이 있다.
# 회귀 - GridSearchCV
param_grid_reg = {
"model__n_estimators": [100, 200],
"model__max_depth": [None, 3, 5, 10]
}
rf_reg_search = GridSearchCV(
estimator=Pipeline([
("preprocessor", preprocessor_reg),
("model", RandomForestRegressor(random_state=42))
]),
param_grid=param_grid_reg,
cv=5,
scoring="r2",
n_jobs=-1
)
rf_reg_search.fit(X_train_reg, y_train_reg)
print("회귀 최적 파라미터:", rf_reg_search.best_params_)
print("회귀 최고 교차검증 점수:", rf_reg_search.best_score_)
4.2 RandomizedSearchCV
RandomizedSearchCV는 가능한 조합 전체를 다 보지 않고, 일부 조합을 무작위로 샘플링해서 탐색한다.
탐색 범위가 넓고 조합 수가 많을 때 더 효율적일 수 있다.
# 분류 - RandomizedSearchCV
param_dist_clf = {
"model__n_estimators": [50, 100, 200, 300],
"model__max_depth": [None, 3, 5, 10, 20],
"model__min_samples_split": [2, 5, 10]
}
rf_clf_search = RandomizedSearchCV(
estimator=Pipeline([
("model", RandomForestClassifier(random_state=42))
]),
param_distributions=param_dist_clf,
n_iter=10,
cv=5,
scoring="accuracy",
random_state=42,
n_jobs=-1
)
rf_clf_search.fit(X_train_clf, y_train_clf)
print("분류 최적 파라미터:", rf_clf_search.best_params_)
print("분류 최고 교차검증 점수:", rf_clf_search.best_score_)
5. 평가 지표 정리
5.1. 회귀 평가 지표 정리
회귀 문제는 예측값과 실제값이 얼마나 차이 나는지를 기준으로 성능을 평가한다.
MAE(Mean Absolute Error) 는 예측값과 실제값 차이의 절댓값 평균이다.
mae = mean_absolute_error(y_test_reg, lr_reg_pred)
- 오차를 직관적으로 이해하기 쉽다.
- 이상치의 영향이 MSE보다 덜하다.
- 작을수록 좋다.
MSE(Mean Squared Error) 는 오차를 제곱해서 평균낸 값이다.
mae = mean_absolute_error(y_test_reg, lr_reg_pred)
- 큰 오차에 더 큰 패널티를 준다.
- 이상치에 민감하다.
- 작을수록 좋다.
RMSE(Root Mean Squared Error) 는 MSE에 제곱근을 취한 값이다.
rmse = np.sqrt(mse)
- 다시 원래 단위로 해석할 수 있어서 직관적이다.
- 큰 오차를 더 민감하게 반영한다.
- 작을수록 좋다.
R² Score 는 모델이 데이터를 얼마나 잘 설명하는지를 보여주는 지표이다.
r2 = r2_score(y_test_reg, lr_reg_pred)
- 1에 가까울수록 좋다.
- 0이면 평균 수준의 예측과 비슷하다고 볼 수 있다.
- 음수가 나올 수도 있는데, 그 경우 평균보다도 못한 예측일 수 있다.
- 클수록 좋다.
5.2. 분류 평가 지표 정리
Accuracy 는 전체 예측 중 정답을 맞힌 비율이다.
acc = accuracy_score(y_test_clf, rf_clf_pred)
- 가장 직관적인 지표이다.
- 데이터가 균형 잡혀 있을 때는 유용하다.
- 클래스 불균형이 심하면 misleading할 수 있다.
- 클수록 좋다.
F1-score 는 Precision과 Recall의 균형을 함께 보는 지표이다.
f1 = f1_score(y_test_clf, rf_clf_pred, average="macro")
- 둘 중 하나만 높고 하나가 낮은 상황을 보완해서 볼 수 있다.
- 클래스 불균형 문제에서 자주 함께 확인한다.
- 클수록 좋다.
Confusion Matrix 는 실제 클래스와 예측 클래스의 조합을 표 형태로 보여준다.
cm = confusion_matrix(y_test_clf, rf_clf_pred)
print("Confusion Matrix:\n", cm)
print(classification_report(y_test_clf, rf_clf_pred))
- 어떤 클래스를 잘 맞추고, 어떤 클래스를 헷갈리는지 확인할 수 있다.
- 다중분류에서도 매우 유용하다.
분류 문제에서는 Accuracy만 보는 것보다 Precision, Recall, F1-score, Confusion Matrix까지 함께 보는 것이 훨씬 안전하다.
6. Feature Importance / Permutation Importance
모델을 학습한 뒤에는 단순히 성능만 보는 것이 아니라, 어떤 feature가 예측에 많이 기여했는지 확인하고 싶을 때가 있다.
이때 자주 사용하는 것이 Feature Importance와 Permutation Importance이다.
6.1. Feature Importance
Feature Importance는 주로 트리 계열 모델에서 많이 사용한다.
각 feature가 분할에 얼마나 기여했는지를 기준으로 중요도를 계산한다.
rf_importance_model = RandomForestClassifier(random_state=42)
rf_importance_model.fit(X_train_clf, y_train_clf)
feature_importance_df = pd.DataFrame({
"feature": X_train_clf.columns,
"importance": rf_importance_model.feature_importances_
}).sort_values("importance", ascending=False)
print(feature_importance_df)
이 값이 높을수록 모델이 해당 변수를 더 많이 참고했다는 뜻으로 해석할 수 있다.
다만 트리 기반 모델에 의존적이라는 점을 기억할 필요가 있다.
6.2. Permutation Importance
Permutation Importance는 특정 feature 값을 섞었을 때 모델 성능이 얼마나 떨어지는지를 보는 방식이다.
중요한 feature라면 값을 섞었을 때 성능 하락이 크게 나타난다.
perm_result = permutation_importance(
rf_importance_model,
X_test_clf,
y_test_clf,
n_repeats=10,
random_state=42,
scoring="accuracy"
)
perm_importance_df = pd.DataFrame({
"feature": X_test_clf.columns,
"importance_mean": perm_result.importances_mean
}).sort_values("importance_mean", ascending=False)
print(perm_importance_df)
이 방법은 특정 모델에 덜 종속적이어서 활용 범위가 더 넓다.
7. 모델 평가 시각화
7.1 회귀 시각화
회귀 문제에서는 숫자 지표만 보는 것보다 예측 결과를 시각적으로 확인하는 것이 훨씬 이해하기 쉽다.
같은 데이터셋이라도 모델마다 예측 방식이 다르기 때문에, 성능 비교표와 함께 그래프를 보면 어떤 모델이 더 안정적으로 예측하는지 빠르게 파악할 수 있다.
모델별 R² 비교 막대그래프
먼저 모델별 R² 비교 그래프를 그리면 전체적인 설명력을 한눈에 볼 수 있다.
R²가 높을수록 실제 데이터의 흐름을 더 잘 설명한다고 볼 수 있다.
plt.figure(figsize=(10, 5))
sns.barplot(data=reg_results_df, x="Model", y="R2")
plt.xticks(rotation=45)
plt.title("Regression Model R2 Comparison")
plt.tight_layout()
plt.show()

실제값 vs 예측값 산점도
실제값과 예측값 산점도도 자주 사용한다.
이 그래프에서 점들이 대각선 근처에 모일수록 예측이 잘된 것이다.
점들이 넓게 퍼져 있으면 실제값과 예측값 차이가 크다는 뜻이다.
plt.figure(figsize=(6, 6))
plt.scatter(y_test_reg, best_reg_pred, alpha=0.7)
plt.plot(
[y_test_reg.min(), y_test_reg.max()],
[y_test_reg.min(), y_test_reg.max()],
linestyle="--"
)
plt.xlabel("Actual Tip")
plt.ylabel("Predicted Tip")
plt.title(f"Actual vs Predicted ({best_reg_name})")
plt.tight_layout()
plt.show()

잔차 시각화
잔차는 실제값에서 예측값을 뺀 값이며, 모델이 어디에서 얼마나 틀렸는지 보여준다.
잔차 분포가 0 근처에 고르게 모이면 비교적 안정적인 예측이라고 볼 수 있다.
반대로 특정 방향으로 치우치거나 이상하게 퍼져 있다면, 모델이 어떤 구간에서 지속적으로 과대예측 또는 과소예측하고 있을 가능성이 있다.
plt.figure(figsize=(8, 5))
plt.scatter(best_reg_pred, residuals, alpha=0.7)
plt.axhline(0, linestyle="--")
plt.xlabel("Predicted Value")
plt.ylabel("Residual")
plt.title(f"Residual Plot ({best_reg_name})")
plt.tight_layout()
plt.show()

7.2 분류 시각화
분류 문제에서는 단순히 Accuracy만 보는 것보다, 모델이 어떤 클래스를 잘 맞추고 어떤 클래스를 헷갈리는지를 함께 보는 것이 중요하다.
Accuracy 비교 막대그래프
plt.figure(figsize=(10, 5))
sns.barplot(data=clf_results_df, x="Model", y="Accuracy")
plt.xticks(rotation=45)
plt.title("Classification Model Accuracy Comparison")
plt.tight_layout()
plt.show()

Confusion Matrix heatmap
Confusion Matrix는 분류 문제에서 가장 대표적인 시각화이다.
실제 클래스와 예측 클래스의 조합을 표 형태로 보여주기 때문에, 어떤 클래스를 정확히 맞추고 어떤 클래스를 혼동하는지 바로 확인할 수 있다.
다중분류 문제인 iris 데이터셋에서도 각 품종이 얼마나 잘 분류되는지 직관적으로 볼 수 있다.
cm = confusion_matrix(y_test_clf, best_clf_pred)
plt.figure(figsize=(6, 5))
sns.heatmap(cm, annot=True, fmt="d", cmap="Blues")
plt.title(f"Confusion Matrix ({best_clf_name})")
plt.xlabel("Predicted Label")
plt.ylabel("True Label")
plt.tight_layout()
plt.show()

이번 글에서는 회귀와 분류 문제를 나누어 대표적인 머신러닝 모델의 기본 사용법을 살펴보고, 교차검증과 하이퍼파라미터 튜닝, 평가 지표, 그리고 시각화 방법까지 함께 정리했다.
모델을 선택할때 해석이 쉬운 LinearRegression, LogisticRegression 같은 기본 모델로 시작하고, 이후 비선형 패턴이 의심되면 DecisionTree, RandomForest, GradientBoosting, SVC 등을 비교하는 방식이 일반적이다. 데이터 스케일에 민감한 KNN, SVC 계열은 스케일링 여부를 특히 신경 써야 한다.
머신러닝에서는 모델 하나만 학습해보는 것보다 여러 모델을 같은 기준으로 비교해보는 과정이 중요하다.
또한 성능 수치만 보는 데서 끝나지 않고, 실제 예측 결과와 오차, 클래스별 분류 결과, 변수 중요도까지 함께 확인해야 모델을 더 정확하게 이해할 수 있다.
'AI dev > Machine Learning' 카테고리의 다른 글
| 추가로 알아두면 좋은 전처리: PCA, Vectorization, SMOTE (0) | 2026.04.07 |
|---|---|
| ML - 데이터 전처리 (0) | 2026.04.04 |