본문으로 건너뛰기
Advertisement

주요 알고리즘 — 선형 회귀, 랜덤 포레스트, k-NN

머신러닝의 핵심 알고리즘을 원리부터 실전 코드까지 비교합니다.


선형 회귀 (Linear Regression)

from sklearn.linear_model import (
LinearRegression,
Ridge, # L2 규제
Lasso, # L1 규제 (특성 선택 효과)
ElasticNet, # L1 + L2 결합
)
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import numpy as np

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

scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train)
X_test_s = scaler.transform(X_test)

# 기본 선형 회귀
lr = LinearRegression()
lr.fit(X_train_s, y_train)

print(f"계수: {lr.coef_}")
print(f"절편: {lr.intercept_:.4f}")
print(f"R² (학습): {lr.score(X_train_s, y_train):.4f}")
print(f"R² (테스트): {lr.score(X_test_s, y_test):.4f}")

# Ridge (L2 규제 — 계수 크기 제한)
ridge = Ridge(alpha=1.0)
ridge.fit(X_train_s, y_train)
print(f"Ridge R²: {ridge.score(X_test_s, y_test):.4f}")

# Lasso (L1 규제 — 불필요한 특성 계수 → 0)
lasso = Lasso(alpha=0.1)
lasso.fit(X_train_s, y_train)
nonzero = np.sum(lasso.coef_ != 0)
print(f"Lasso 0이 아닌 계수 수: {nonzero}/{len(lasso.coef_)}")

로지스틱 회귀 (분류)

from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_breast_cancer

X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=42)

scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train)
X_test_s = scaler.transform(X_test)

lr_clf = LogisticRegression(C=1.0, max_iter=1000, random_state=42)
lr_clf.fit(X_train_s, y_train)

# 클래스 확률
probs = lr_clf.predict_proba(X_test_s) # [[P(0), P(1)], ...]
print(f"첫 샘플 확률: 음성={probs[0,0]:.3f}, 양성={probs[0,1]:.3f}")

결정 트리 (Decision Tree)

from sklearn.tree import DecisionTreeClassifier, export_text, plot_tree
import matplotlib.pyplot as plt

dt = DecisionTreeClassifier(
max_depth=4, # 과적합 방지
min_samples_leaf=5, # 리프 노드 최소 샘플
random_state=42,
)
dt.fit(X_train, y_train)

# 트리 시각화
plt.figure(figsize=(20, 8))
plot_tree(dt, feature_names=feature_names, class_names=["악성", "양성"],
filled=True, fontsize=8)
plt.show()

# 텍스트로 출력
print(export_text(dt, feature_names=feature_names))

랜덤 포레스트 (Random Forest)

from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor

# 분류
rf = RandomForestClassifier(
n_estimators=200, # 트리 수
max_depth=10, # 최대 깊이
min_samples_split=5,
max_features="sqrt", # 각 분기에서 고려할 특성 수
n_jobs=-1, # 병렬 처리
random_state=42,
)
rf.fit(X_train, y_train)
print(f"RF 정확도: {rf.score(X_test, y_test):.4f}")

# OOB (Out-of-Bag) 점수 — 추가 검증 없이 모델 평가
rf_oob = RandomForestClassifier(n_estimators=100, oob_score=True, random_state=42)
rf_oob.fit(X_train, y_train)
print(f"OOB 점수: {rf_oob.oob_score_:.4f}")

# 특성 중요도 시각화
import pandas as pd
feat_imp = pd.Series(rf.feature_importances_, index=feature_names).sort_values(ascending=False)
print(feat_imp.head(10))

k-NN (k-최근접 이웃)

from sklearn.neighbors import KNeighborsClassifier, KNeighborsRegressor

# k값에 따른 성능 비교
from sklearn.model_selection import cross_val_score

k_values = range(1, 31)
cv_scores = []

for k in k_values:
knn = KNeighborsClassifier(n_neighbors=k, metric="euclidean")
scores = cross_val_score(knn, X_train_s, y_train, cv=5, scoring="accuracy")
cv_scores.append(scores.mean())

best_k = k_values[np.argmax(cv_scores)]
print(f"최적 k: {best_k}, 점수: {max(cv_scores):.4f}")

# 최적 k로 학습
knn = KNeighborsClassifier(n_neighbors=best_k)
knn.fit(X_train_s, y_train)
print(f"테스트 정확도: {knn.score(X_test_s, y_test):.4f}")

SVM (서포트 벡터 머신)

from sklearn.svm import SVC, SVR

# 분류
svm = SVC(
C=1.0, # 마진-오분류 균형 (클수록 오분류 적음)
kernel="rbf", # 'linear', 'poly', 'rbf', 'sigmoid'
gamma="scale",
probability=True, # predict_proba 사용 시 필요
random_state=42,
)
svm.fit(X_train_s, y_train)
print(f"SVM 정확도: {svm.score(X_test_s, y_test):.4f}")

알고리즘 비교

from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC

models = {
"Logistic Regression": LogisticRegression(max_iter=1000, random_state=42),
"Decision Tree": DecisionTreeClassifier(max_depth=5, random_state=42),
"Random Forest": RandomForestClassifier(n_estimators=100, random_state=42),
"Gradient Boosting": GradientBoostingClassifier(n_estimators=100, random_state=42),
"k-NN (k=5)": KNeighborsClassifier(n_neighbors=5),
"SVM": SVC(random_state=42),
}

results = {}
for name, model in models.items():
scores = cross_val_score(model, X_train_s, y_train, cv=5, scoring="accuracy")
results[name] = {"mean": scores.mean(), "std": scores.std()}
print(f"{name:25s}: {scores.mean():.4f} ± {scores.std():.4f}")

알고리즘 선택 가이드

데이터 크기와 특성에 따라 알고리즘 선택:

소규모 데이터 (< 10K):
분류 → SVM, Logistic Regression, k-NN
회귀 → Ridge, Lasso

중간 규모 (10K ~ 100K):
분류/회귀 → Random Forest, Gradient Boosting

대규모 (> 100K):
분류/회귀 → SGDClassifier/Regressor, XGBoost, LightGBM

해석 필요:
→ Logistic Regression, Decision Tree

비선형 복잡 패턴:
→ Random Forest, Gradient Boosting, SVM(RBF)

정리

알고리즘유형강점약점
선형 회귀회귀해석 용이, 빠름비선형 관계 취약
로지스틱 회귀분류확률 출력, 해석 용이비선형 패턴 취약
결정 트리분류/회귀해석 쉬움과적합 위험
랜덤 포레스트분류/회귀강건, 특성 중요도느림, 메모리
k-NN분류/회귀간단, 직관적예측 느림, 스케일 민감
SVM분류/회귀고차원 효과적대규모 데이터 느림

실무에서는 Random Forest → Gradient Boosting (XGBoost/LightGBM) 순서로 시도하는 것이 일반적입니다.

Advertisement