๋จธ์ ๋ฌ๋ ์๊ณ ๋ฆฌ์ฆ ์๋ฒฝ ํด์ค: ๊ธฐ์ ๋ฉด์ ์ ์ํ ์ข ํฉ ๊ฐ์ด๋
๋จธ์ ๋ฌ๋ ์๊ณ ๋ฆฌ์ฆ ๊ธฐ์ ๋ฉด์ ๊ฐ์ด๋. ์ ํ ๋ชจ๋ธ, ์์ฌ๊ฒฐ์ ํธ๋ฆฌ, ์์๋ธ, ํด๋ฌ์คํฐ๋ง, ํ๊ฐ ์งํ, ์ ๊ทํ๋ฅผ scikit-learn ์ฝ๋์ ํจ๊ป ์ฒด๊ณ์ ์ผ๋ก ํด์คํฉ๋๋ค.

2026๋ ๋ฐ์ดํฐ ์ฌ์ด์ธ์ค ๊ธฐ์ ๋ฉด์ ์์ ๋จธ์ ๋ฌ๋ ์๊ณ ๋ฆฌ์ฆ์ ๋ํ ๊น์ด ์๋ ์ดํด๋ ํ์ ์ญ๋์ผ๋ก ์๋ฆฌ์ก์์ต๋๋ค. ์ฃผ๋์ด ๋ฐ์ดํฐ ์ฌ์ด์ธํฐ์คํธ๋ถํฐ ์๋์ด ML ์์ง๋์ด๊น์ง, ๋ฉด์ ๊ด์ ์ง์์๊ฐ ํต์ฌ ์๊ณ ๋ฆฌ์ฆ ๊ตฐ์ ์ค๋ช ํ๊ณ ๊ตฌํํ๋ฉฐ ๋น๊ต ๋ถ์ํ ์ ์๋ ๋ฅ๋ ฅ์ ๊ธฐ๋ํฉ๋๋ค. ์ ํ ๋ชจ๋ธ์์ ์์๋ธ ๊ธฐ๋ฒ, ๋น์ง๋ํ์ต ๊ธฐ๋ฒ๊น์ง scikit-learn 1.8 ๊ธฐ๋ฐ์ Python ๊ตฌํ๊ณผ ํ๊ฐ ์ ๋ต, ๊ทธ๋ฆฌ๊ณ ๋ฉด์ ์์ ํฉ๊ฒฉ๊ณผ ๋ถํฉ๊ฒฉ์ ๊ฐ๋ฅด๋ ์ ํํ ํธ๋ ์ด๋์คํ๋ฅผ ์ฒด๊ณ์ ์ผ๋ก ์ดํด๋ด ๋๋ค.
๋จธ์ ๋ฌ๋ ์๊ณ ๋ฆฌ์ฆ์ ์ง๋ํ์ต(ํ๊ท, ๋ถ๋ฅ), ๋น์ง๋ํ์ต(ํด๋ฌ์คํฐ๋ง, ์ฐจ์ ์ถ์), ๊ฐํํ์ต์ ์ธ ๊ฐ์ง ๊ณ์ด๋ก ๋ถ๋ฅ๋ฉ๋๋ค. 2026๋ ๊ธฐ์ ๋ฉด์ ์์๋ ์์ ๋ ๊ณ์ด์ ์ง์ค์ ์ผ๋ก ์ถ์ ๋๋ฉฐ, ํนํ ์ํฉ์ ๋ฐ๋ฅธ ์๊ณ ๋ฆฌ์ฆ ์ ํ ๊ธฐ์ค๊ณผ ๊ฒฐ๊ณผ ํ๊ฐ ๋ฐฉ๋ฒ์ ๋ํ ์ง๋ฌธ์ด ๋น๋ฒํฉ๋๋ค.
์ง๋ํ์ต: ํ๊ท์ ๋ถ๋ฅ์ ๊ธฐ์ด
์ง๋ํ์ต ์๊ณ ๋ฆฌ์ฆ์ ๋ ์ด๋ธ์ด ๋ถ์ฌ๋ ๋ฐ์ดํฐ๋ก๋ถํฐ ํ์ตํฉ๋๋ค. ๊ฐ ํ๋ จ ์ํ์ ์ ๋ ฅ๊ฐ๊ณผ ๊ธฐ๋ ์ถ๋ ฅ๊ฐ์ ์์ผ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค. ํ๊ท(Regression)๋ ์ฐ์์ ์ธ ๊ฐ(์ฃผํ ๊ฐ๊ฒฉ, ๊ธฐ์จ ๋ฑ)์ ์์ธกํ๊ณ , ๋ถ๋ฅ(Classification)๋ ์ด์ฐ์ ์ธ ๋ ์ด๋ธ(์คํธ ์ฌ๋ถ, ์ง๋ณ ์ง๋จ ๋ฑ)์ ํ ๋นํฉ๋๋ค. ๋ ๊ฐ์ง ๋ชจ๋ ๋ฐ์ดํฐ ์ฌ์ด์ธ์ค ๋ฉด์ ์์ ๋ฐ๋์ ์ดํดํด์ผ ํ๋ ์์ญ์ ๋๋ค.
์ ํ ํ๊ท๋ ๋ชจ๋ ํ๊ท ๊ณผ์ ์ ์ถ๋ฐ์ ์ ๋๋ค. ํน์ฑ(feature)๊ณผ ํ๊ฒ ๋ณ์ ๊ฐ์ ๊ด๊ณ๋ฅผ ๊ฐ์คํฉ์ผ๋ก ๋ชจ๋ธ๋งํ๋ฉฐ, ๋ฉด์ ๊ด์ ์ง์์์๊ฒ ์ง์ ๊ตฌํํ๊ณ , ๋น์ฉ ํจ์(cost function)๋ฅผ ์ค๋ช ํ๋ฉฐ, ๋ชจ๋ธ์ด ์คํจํ๋ ์ํฉ์ ๋ ผ์ํ ๊ฒ์ ์๊ตฌํฉ๋๋ค.
# linear_regression_demo.py
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
# Generate synthetic housing data: square footage -> price
np.random.seed(42)
sqft = np.random.uniform(500, 3000, size=200).reshape(-1, 1)
price = 150 * sqft.flatten() + np.random.normal(0, 20000, size=200)
X_train, X_test, y_train, y_test = train_test_split(sqft, price, test_size=0.2)
model = LinearRegression()
model.fit(X_train, y_train) # Fit on training data
predictions = model.predict(X_test) # Predict on unseen data
print(f"Coefficient: {model.coef_[0]:.2f}") # Weight per sqft
print(f"R2 Score: {r2_score(y_test, predictions):.4f}")
print(f"RMSE: {np.sqrt(mean_squared_error(y_test, predictions)):.2f}")ํ๊ท ๊ณ์(coefficient)๋ ๋ฉด์ ์ด 1 ์ ๊ณฑํผํธ ์ฆ๊ฐํ ๋ ๊ฐ๊ฒฉ์ด ์ผ๋ง๋ ๋ณ๋ํ๋์ง๋ฅผ ๋ํ๋ ๋๋ค. R2 ์ ์์ RMSE๋ ์์ธก ํ์ง์ ์ ๋ํํ๋ ํต์ฌ ์งํ์ด๋ฉฐ, ๋ฉด์ ๊ด์ ์ง์์๊ฐ ์ด ๋ ์งํ๋ฅผ ์ฆ์ ํด์ํ ์ ์๊ธฐ๋ฅผ ๊ธฐ๋ํฉ๋๋ค.
๋ถ๋ฅ ๋ฌธ์ ์์๋ ๋ก์ง์คํฑ ํ๊ท๊ฐ ์๊ทธ๋ชจ์ด๋ ํจ์๋ฅผ ์ ์ฉํ์ฌ ํ๋ฅ ๊ฐ์ ์ถ๋ ฅํฉ๋๋ค. ์ด๋ฆ์ "ํ๊ท"๊ฐ ํฌํจ๋์ด ์์ง๋ง ์ค์ ๋ก๋ ๋ถ๋ฅ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. ๊ฒฐ์ ๊ฒฝ๊ณ(decision boundary), ์ ๊ทํ ๋งค๊ฐ๋ณ์ C, ์ด์ง ๋ถ๋ฅ์ ๋ค์ค ํด๋์ค ๋ถ๋ฅ์ ์ฐจ์ด์ ์ ๋ชจ๋ ๋น์ถ ๋ฉด์ ์ฃผ์ ์ ๋๋ค.
# logistic_classification.py
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
data = load_breast_cancer() # Binary classification dataset
X_train, X_test, y_train, y_test = train_test_split(
data.data, data.target, test_size=0.2, random_state=42
)
clf = LogisticRegression(max_iter=5000, C=1.0) # C controls regularization strength
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
print(classification_report(y_test, y_pred, target_names=data.target_names))๋ถ๋ฅ ๋ฆฌํฌํธ๋ ํด๋์ค๋ณ ์ ๋ฐ๋(precision), ์ฌํ์จ(recall), F1 ์ ์๋ฅผ ๋ณด์ฌ์ค๋๋ค. ์ด ๋ฆฌํฌํธ๋ฅผ ์ ์ฐฝํ๊ฒ ์ฝ์ด๋ด๋ ์ฐ์ต์ด ํ์ํฉ๋๋ค. ๋ฉด์ ๊ด์ ์ง์์๊ฐ ํด์์ ๋จธ๋ญ๊ฑฐ๋ฆฌ๋ ์๊ฐ์ ๋์น์ง ์์ต๋๋ค.
์์ฌ๊ฒฐ์ ํธ๋ฆฌ์ ์์๋ธ ๊ธฐ๋ฒ
์์ฌ๊ฒฐ์ ํธ๋ฆฌ(Decision Tree)๋ ํน์ฑ์ ์๊ณ๊ฐ์ ๊ธฐ์ค์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฌ๊ท์ ์ผ๋ก ๋ถํ ํฉ๋๋ค. ๋จ๋ ์ผ๋ก ์ฌ์ฉํ๋ฉด ๊ณผ์ ํฉ(overfitting)์ด ์ฝ๊ฒ ๋ฐ์ํฉ๋๋ค. ๋๋ค ํฌ๋ ์คํธ(Random Forest)์ ๊ทธ๋๋์ธํธ ๋ถ์คํ (Gradient Boosting) ๊ฐ์ ์์๋ธ ๊ธฐ๋ฒ์ ์ฌ๋ฌ ํธ๋ฆฌ๋ฅผ ๊ฒฐํฉํ์ฌ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค. ํด์ ๊ฐ๋ฅ์ฑ๊ณผ ์ฑ๋ฅ ์ฌ์ด์ ๊ท ํ์ด ๋ฐ์ด๋๊ธฐ ๋๋ฌธ์ ๊ฑฐ์ ๋ชจ๋ ML ๋ฉด์ ์ ๋ฑ์ฅํ๋ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค.
๋๋ค ํฌ๋ ์คํธ๋ ๋ถํธ์คํธ๋ฉ ์ํ๋ก ๋ ๋ฆฝ์ ์ธ ํธ๋ฆฌ๋ฅผ ์ฌ๋ฌ ๊ฐ ๊ตฌ์ถํ ๋ค ์์ธก๊ฐ์ ํ๊ท ํฉ๋๋ค. ์ด ๊ณผ์ ์ ํธํฅ(bias)์ ์ฆ๊ฐ์ํค์ง ์์ผ๋ฉด์ ๋ถ์ฐ(variance)์ ์ค์ ๋๋ค. ๋ฐฐ๊น (bagging)๊ณผ ๋ถ์คํ (boosting)์ ์ฐจ์ด, ํน์ฑ ์ค์๋(feature importance), OOB(Out-of-Bag) ์ค์ฐจ ์ถ์ ์ ๋ฉด์ ์์ ์์ฃผ ๊ฒ์ฆ๋๋ ๊ฐ๋ ์ ๋๋ค.
# ensemble_comparison.py
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.datasets import load_wine
from sklearn.model_selection import cross_val_score
data = load_wine() # 3-class classification
X, y = data.data, data.target
# Random Forest: parallel trees, reduces variance
rf = RandomForestClassifier(n_estimators=100, max_depth=5, random_state=42)
rf_scores = cross_val_score(rf, X, y, cv=5, scoring='accuracy')
# Gradient Boosting: sequential trees, reduces bias
gb = GradientBoostingClassifier(n_estimators=100, learning_rate=0.1, max_depth=3)
gb_scores = cross_val_score(gb, X, y, cv=5, scoring='accuracy')
print(f"Random Forest: {rf_scores.mean():.4f} +/- {rf_scores.std():.4f}")
print(f"Gradient Boosting: {gb_scores.mean():.4f} +/- {gb_scores.std():.4f}")๋๋ค ํฌ๋ ์คํธ๋ ์์ ์ฑ๊ณผ ์ ์ ํ๋ ๋ ธ๋ ฅ์ด ์๊ตฌ๋ ๋ ํ์ํ ์ฑ๋ฅ์ ๋ฐํํฉ๋๋ค. ๊ทธ๋๋์ธํธ ๋ถ์คํ ์ ์ข ์ข ๋ ๋์ ์ ํ๋๋ฅผ ๋ฌ์ฑํ์ง๋ง, ํ์ต๋ฅ (learning rate), ์ถ์ ๊ธฐ ์(n_estimators), ํธ๋ฆฌ ๊น์ด(max_depth) ๋ฑ ํ์ดํผํ๋ผ๋ฏธํฐ์ ์ํธ์์ฉ์ ๋ํ ์ธ๋ฐํ ์กฐ์ ์ด ํ์ํฉ๋๋ค. ๋ฉด์ ๊ด์ด ๊ฒ์ฆํ๊ณ ์ ํ๋ ๊ฒ์ ๋จ์ํ ์ด๋ค ์ซ์๊ฐ ๋ ํฐ์ง๊ฐ ์๋๋ผ, ์ด ํธ๋ ์ด๋์คํ๋ฅผ ์ดํดํ๊ณ ์๋์ง ์ฌ๋ถ์ ๋๋ค.
| ๊ธฐ์ค | ๋๋ค ํฌ๋ ์คํธ | ๊ทธ๋๋์ธํธ ๋ถ์คํ |
|---|---|---|
| ํ์ต ์๋ | ๋น ๋ฆ (๋ณ๋ ฌ ์ฒ๋ฆฌ) | ๋๋ฆผ (์์ฐจ ์ฒ๋ฆฌ) |
| ๊ณผ์ ํฉ ์ํ | ๋ฎ์ | ํ๋ ์์ด๋ ๋์ |
| ํ์ดํผํ๋ผ๋ฏธํฐ ๋ฏผ๊ฐ๋ | ๋ฎ์ | ๋์ |
| ํน์ฑ ์ค์๋ | ๋ด์ฅ (๋ถ์๋ ๊ธฐ๋ฐ) | ๋ด์ฅ (์ด๋ ๊ธฐ๋ฐ) |
| ์ต์ ํ์ฉ | ๋ฒ ์ด์ค๋ผ์ธ ๋ชจ๋ธ, ๋ ธ์ด์ฆ๊ฐ ๋ง์ ๋ฐ์ดํฐ | ๋ํ, ์ ํ ๋ฐ์ดํฐ |
๋น์ง๋ํ์ต: ํด๋ฌ์คํฐ๋ง๊ณผ ์ฐจ์ ์ถ์
๋น์ง๋ํ์ต ์๊ณ ๋ฆฌ์ฆ์ ๋ ์ด๋ธ์ด ์๋ ๋ฐ์ดํฐ์์ ๊ตฌ์กฐ๋ฅผ ๋ฐ๊ฒฌํฉ๋๋ค. K-Means ํด๋ฌ์คํฐ๋ง๊ณผ PCA(์ฃผ์ฑ๋ถ ๋ถ์)๋ ๋ฉด์ ์์ ๊ฐ์ฅ ๋น๋ฒํ๊ฒ ์ถ์ ๋๋ ๋ ๊ฐ์ง ๊ธฐ๋ฒ์ ๋๋ค. ๋ ๊ธฐ๋ฒ ๋ชจ๋์ ๋ํ ์๋ฌ์ด ํ์์ ์ ๋๋ค.
K-Means๋ ํด๋ฌ์คํฐ ๋ด ๋ถ์ฐ์ ์ต์ํํ์ฌ ๋ฐ์ดํฐ๋ฅผ k๊ฐ์ ํด๋ฌ์คํฐ๋ก ๋ถํ ํฉ๋๋ค. ์๊ณ ๋ฆฌ์ฆ์ ๊ฐ ๋ฐ์ดํฐ ํฌ์ธํธ๋ฅผ ๊ฐ์ฅ ๊ฐ๊น์ด ์ค์ฌ์ (centroid)์ ํ ๋นํ๊ณ , ์ค์ฌ์ ์ ๊ฐฑ์ ํ๋ ๊ณผ์ ์ ๋ฐ๋ณตํฉ๋๋ค. ๋ฉด์ ์์ ์์ฃผ ๋ฑ์ฅํ๋ ๋ ๊ฐ์ง ํต์ฌ ์ง๋ฌธ์ k๊ฐ์ ์ด๋ป๊ฒ ์ ํํ๋์ง(์๋ณด์ฐ ๋ฐฉ๋ฒ, ์ค๋ฃจ์ฃ ์ ์)์ ๋น๊ตฌํ(non-spherical) ํด๋ฌ์คํฐ์์ ์ด๋ค ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋์ง์ ๋๋ค.
# kmeans_clustering.py
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import silhouette_score
from sklearn.datasets import load_iris
data = load_iris()
X = StandardScaler().fit_transform(data.data) # Scale features first
# Test multiple values of k to find optimal cluster count
for k in [2, 3, 4, 5]:
kmeans = KMeans(n_clusters=k, n_init=10, random_state=42)
labels = kmeans.fit_predict(X)
sil = silhouette_score(X, labels) # Higher = better-defined clusters
inertia = kmeans.inertia_ # Within-cluster sum of squares
print(f"k={k}: silhouette={sil:.3f}, inertia={inertia:.1f}")ํด๋ฌ์คํฐ๋ง ์ ์ ํน์ฑ์ ์ค์ผ์ผ๋งํ๋ ๊ฒ์ ํ์ ์ฌํญ์ ๋๋ค. K-Means๋ ์ ํด๋ฆฌ๋ ๊ฑฐ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฏ๋ก, ์ค์ผ์ผ์ด ํฐ ํน์ฑ์ด ๊ฑฐ๋ฆฌ ๊ณ์ฐ์ ์ง๋ฐฐํ๊ฒ ๋ฉ๋๋ค. ์ด ์ธ๋ถ ์ฌํญ์ ๋ฉด์ ์์ ๋ฐ๋ณต์ ์ผ๋ก ํ์ธ๋๋ ํฌ์ธํธ์ ๋๋ค.
PCA๋ ๋ฐ์ดํฐ๋ฅผ ์ต๋ ๋ถ์ฐ ๋ฐฉํฅ์ผ๋ก ํฌ์ํ์ฌ ์ฐจ์์ ์ถ์ํฉ๋๋ค. ์๊ฐํ(2D/3D ํฌ์)์ ์ ์ฒ๋ฆฌ(๋ ธ์ด์ฆ ์ ๊ฑฐ, ํ์ ๋ชจ๋ธ์ ์๋ ํฅ์)๋ผ๋ ๋ ๊ฐ์ง ๋ชฉ์ ์ผ๋ก ํ์ฉ๋ฉ๋๋ค. ๋ฉด์ ๊ด์ ์ง์์๊ฐ ์ค๋ช ๋ถ์ฐ ๋น์จ(explained variance ratio)์ ํด์ํ๊ณ ์ ์ ํ ์ฃผ์ฑ๋ถ ์๋ฅผ ์ ํํ๋ ๋ฐฉ๋ฒ์ ์ค๋ช ํ ์ ์๊ธฐ๋ฅผ ๊ธฐ๋ํฉ๋๋ค.
PCA๋ ํน์ฑ ๊ฐ ์๊ด๊ด๊ณ๊ฐ ๋๊ณ ์ ํธ๊ฐ ์์์ ๋ฐฉํฅ์ ์ง์ค๋์ด ์์ ๋ ๊ฐ์ฅ ํจ๊ณผ์ ์ ๋๋ค. ๋ฐ๋ฉด์ ํฌ์(sparse)ํ๊ณ ๊ณ ์ฐจ์์ธ ๋ฐ์ดํฐ(ํ ์คํธ, ์-ํซ ์ธ์ฝ๋ฉ๋ ๋ฒ์ฃผํ ๋ณ์ ๋ฑ)์์๋ PCA๊ฐ ์ ์ฉํ ๊ตฌ์กฐ๋ฅผ ํ๊ดดํ ์ ์์ต๋๋ค. ์ด๋ฌํ ๊ฒฝ์ฐ์๋ Truncated SVD๋ ํนํ๋ ์๋ฒ ๋ฉ ๊ธฐ๋ฒ์ด ๋ ์ ํฉํฉ๋๋ค.
๋ชจ๋ธ ํ๊ฐ ์งํ์ ๊ต์ฐจ ๊ฒ์ฆ
์ ์ ํ ํ๊ฐ ์งํ๋ฅผ ์ ํํ๋ ๊ฒ์ ์ ์ ํ ์๊ณ ๋ฆฌ์ฆ์ ์ ํํ๋ ๊ฒ๋ณด๋ค ๋ ์ค์ํฉ๋๋ค. ๋ถ๊ท ํ ๋ฐ์ดํฐ(์ฌ๊ธฐ ๋น์จ 1%)์์ 99% ์ ํ๋๋ฅผ ๋ณด์ด๋ ๋ชจ๋ธ์ ๋จ์ํ ๋ชจ๋ ์ผ์ด์ค๋ฅผ "์ฌ๊ธฐ ์๋"์ผ๋ก ์์ธกํ๋ ๊ฒ์ผ ์ ์์ต๋๋ค. ๋ฉด์ ๊ด์ ํ๊ฐ ์งํ ๊ด๋ จ ์ง๋ฌธ์ ํตํด ์ง์์์ ์ค๋ฌด์ ํ๋จ๋ ฅ์ ๊ฒ์ฆํฉ๋๋ค.
๋ถ๋ฅ ๋ฌธ์ ์์ ๋ฉด์ ์ ๊ฐ์ฅ ์์ฃผ ๋ฑ์ฅํ๋ ๋ค ๊ฐ์ง ์งํ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ์ ๋ฐ๋(Precision): ์์ฑ์ผ๋ก ์์ธกํ ๊ฒ ์ค ์ค์ ์์ฑ์ ๋น์จ์ ๋๋ค. ๊ฑฐ์ง ์์ฑ(FP)์ ๋น์ฉ์ด ๋์ ๋ ์ค์ํฉ๋๋ค(์คํธ ํํฐ๋ง ๋ฑ).
- ์ฌํ์จ(Recall): ์ค์ ์์ฑ ์ค ์ฌ๋ฐ๋ฅด๊ฒ ํ์งํ ๋น์จ์ ๋๋ค. ๊ฑฐ์ง ์์ฑ(FN)์ ๋น์ฉ์ด ๋์ ๋ ์ค์ํฉ๋๋ค(์ง๋ณ ๊ฒ์ง ๋ฑ).
- F1 ์ ์: ์ ๋ฐ๋์ ์ฌํ์จ์ ์กฐํ ํ๊ท ์ ๋๋ค. ๋ ๊ฐ์ง ์ค๋ฅ ์ ํ ์ค ์ด๋ ์ชฝ์ด ๋ช ํํ ์ฐ์ธํ์ง ์์ ๋ ๊ท ํ ์กํ ์ ํ์ง์ ๋๋ค.
- AUC-ROC: ๋ชจ๋ ๋ถ๋ฅ ์๊ณ๊ฐ์ ๊ฑธ์น ์์ ํ์ง์ ์ธก์ ํฉ๋๋ค. ๋ชจ๋ธ ๊ฐ ๋น๊ต์ ํ์์ ์ธ ์งํ์ ๋๋ค.
ํ๊ท ๋ฌธ์ ์์๋ RMSE(ํฐ ์ค์ฐจ์ ํ๋ํฐ ๋ถ์ฌ), MAE(์ด์์น์ ๊ฐ๊ฑด), R2(์ค๋ช ๋ ๋ถ์ฐ์ ๋น์จ)๊ฐ ํต์ฌ ์งํ์ ๋๋ค. MAE์ RMSE ์ค ์ด๋ค ๊ฒ์ ์ ํธํด์ผ ํ๋์ง ํ๋จํ ์ ์๋ ๋ฅ๋ ฅ์ ์ค์ง์ ์ธ ์ดํด๋๋ฅผ ๋ํ๋ ๋๋ค.
# evaluation_metrics.py
from sklearn.metrics import (
precision_score, recall_score, f1_score,
roc_auc_score, confusion_matrix
)
import numpy as np
# Simulated predictions on imbalanced data (5% positive class)
np.random.seed(42)
y_true = np.array([1]*50 + [0]*950)
y_pred = np.array([1]*40 + [0]*10 + [1]*30 + [0]*920) # Some errors
print(f"Precision: {precision_score(y_true, y_pred):.3f}") # 40/(40+30) = 0.571
print(f"Recall: {recall_score(y_true, y_pred):.3f}") # 40/(40+10) = 0.800
print(f"F1-Score: {f1_score(y_true, y_pred):.3f}") # Harmonic mean
cm = confusion_matrix(y_true, y_pred)
print(f"
Confusion Matrix:
{cm}")
# [[920, 30], -> TN=920, FP=30
# [10, 40]] -> FN=10, TP=40ํผ๋ ํ๋ ฌ(Confusion Matrix)์ ์ ํํ๊ฒ ์ฝ๋ ๋ฐ๋ ์ฐ์ต์ด ํ์ํฉ๋๋ค. ์ข์๋จ ์ (์ง์์ฑ, TN)๊ณผ ์ฐํ๋จ ์ (์ง์์ฑ, TP)์ ์ฌ๋ฐ๋ฅธ ์์ธก์ ๋ํ๋ ๋๋ค. ๋๊ฐ์ ๋ฐ์ ์ ์ ๋ ๊ฐ์ง ์ ํ์ ์ค๋ฅ๋ฅผ ๋ณด์ฌ์ค๋๋ค. ๋ฉด์ ์์๋ ํผ๋ ํ๋ ฌ์ ์ ์ํ๊ณ ์ ๋ฐ๋์ ์ฌํ์จ์ ์ง์ ๊ณ์ฐํ๋๋ก ์๊ตฌํ๋ ๊ฒฝ์ฐ๊ฐ ๋น๋ฒํฉ๋๋ค.
๊ต์ฐจ ๊ฒ์ฆ(Cross-Validation)๋ ํน๋ณํ ์ฃผ์๊ฐ ํ์ํ ์์ญ์ ๋๋ค. ๋ฉด์ ๊ด์ ๋จ์ ํ๋์์ ๋ถํ ์ด ์ ์ถฉ๋ถํ์ง ์์์ง, k-ํด๋ ๊ต์ฐจ ๊ฒ์ฆ์ด ์ด๋ป๊ฒ ์๋ํ๋์ง, ๊ณ์ธตํ ํด๋(stratified fold)๊ฐ ์ธ์ ํ์ํ์ง(๋ถ๊ท ํ ํด๋์ค) ์ค๋ช ํ ๊ฒ์ ๊ธฐ๋ํฉ๋๋ค. ์๊ณ์ด ๋ฐ์ดํฐ์๋ ์๊ฐ์ ๋ถํ ์ด ํ์์ ์ด๋ผ๋ ์ฌ์ค๋ ๊ฐ๊ณผํด์๋ ์ ๋ฉ๋๋ค. ๋ง์ ์ง์์๊ฐ ์ด ์ ์ ๋์ณ ๊ฐ์ ์ ๋ฐ์ต๋๋ค.
์ ๊ทํ์ ๊ณผ์ ํฉ ๋ฐฉ์ง ์ ๋ต
ํธํฅ-๋ถ์ฐ ํธ๋ ์ด๋์คํ(Bias-Variance Tradeoff)๋ ๋จธ์ ๋ฌ๋ ์ด๋ก ์์ ๊ฐ์ฅ ์ค์ํ ๋จ์ผ ๊ฐ๋ ์ ๋๋ค. ํธํฅ์ด ๋์ผ๋ฉด ๋ชจ๋ธ์ด ์ง๋์น๊ฒ ๋จ์ํ์ฌ ๊ณผ์์ ํฉ(underfitting)์ด ๋ฐ์ํฉ๋๋ค. ๋ถ์ฐ์ด ๋์ผ๋ฉด ๋ชจ๋ธ์ด ์ง๋์น๊ฒ ๋ณต์กํ์ฌ ๊ณผ์ ํฉ(overfitting)์ด ๋ฐ์ํฉ๋๋ค. ๋ชจ๋ ์๊ณ ๋ฆฌ์ฆ ์ ํ๊ณผ ํ์ดํผํ๋ผ๋ฏธํฐ ๊ฒฐ์ ์ ์ด ํธ๋ ์ด๋์คํ๋ฅผ ํ์ํ๋ ๊ณผ์ ์ ๋๋ค.
์ ๊ทํ(Regularization)๋ ํฐ ๊ณ์์ ํ๋ํฐ๋ฅผ ๋ถ๊ณผํ์ฌ ๋ชจ๋ธ ๋ณต์ก๋๋ฅผ ์ ์ดํฉ๋๋ค. ๋ฆฟ์ง ํ๊ท(Ridge, L2)๋ ๊ณ์๋ฅผ 0์ ๊ฐ๊น๊ฒ ์ถ์ํ์ง๋ง ๋ชจ๋ ํน์ฑ์ ์ ์งํฉ๋๋ค. ๋ผ์ ํ๊ท(Lasso, L1)๋ ์ผ๋ถ ๊ณ์๋ฅผ ์ ํํ 0์ผ๋ก ๋ง๋ค์ด ์๋ฌต์ ์ธ ํน์ฑ ์ ํ์ ์ํํฉ๋๋ค. ์๋ผ์คํฑ ๋ท(Elastic Net)์ ๋ ๊ฐ์ง๋ฅผ ๊ฒฐํฉํฉ๋๋ค. ์ด๋ฌํ ๊ตฌ๋ถ์ ๋ถ๋ฅ์ ํ๊ท ๋ฉด์ ๋ชจ๋์์ ๊ฒ์ฆ๋๋ ํต์ฌ ํฌ์ธํธ์ ๋๋ค.
์ ๊ทํ๋ ๊ณ์์ ํฌ๊ธฐ์ ํ๋ํฐ๋ฅผ ๋ถ๊ณผํฉ๋๋ค. ํน์ฑ์ ์ค์ผ์ผ์ด ์๋ก ๋ค๋ฅด๋ฉด(๋์ด๋ ์์ญ ๋จ์, ์๋์ ์๋ง ๋จ์) ํ๋ํฐ๊ฐ ์ค์ผ์ผ์ด ์์ ํน์ฑ์ ๋ถ๊ท ํ์ ์ผ๋ก ์ ์ฉ๋ฉ๋๋ค. Ridge, Lasso, Elastic Net์ ์ ์ฉํ๊ธฐ ์ ์ ๋ฐ๋์ ํน์ฑ์ ํ์คํํด์ผ ํฉ๋๋ค. ์ด๋ฅผ ์๋ ๊ฒ์ ๋ฉด์ ์์ ์์ฃผ ๋ฐ์ํ๋ ์ค์์ ๋๋ค.
# regularization_comparison.py
from sklearn.linear_model import Ridge, Lasso, ElasticNet
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_diabetes
X, y = load_diabetes(return_X_y=True)
models = {
"Ridge (L2)": make_pipeline(StandardScaler(), Ridge(alpha=1.0)),
"Lasso (L1)": make_pipeline(StandardScaler(), Lasso(alpha=0.1)),
"ElasticNet (L1+L2)": make_pipeline(StandardScaler(), ElasticNet(alpha=0.1, l1_ratio=0.5)),
}
for name, model in models.items():
scores = cross_val_score(model, X, y, cv=5, scoring='r2')
print(f"{name:25s} R2: {scores.mean():.4f} +/- {scores.std():.4f}")ํ์ดํ๋ผ์ธ(Pipeline)์ ์ค์ผ์ผ๋ง๊ณผ ์ ๊ทํ๊ฐ ํจ๊ป ์ด๋ฃจ์ด์ง๋๋ก ๋ณด์ฅํ์ฌ, ํ ์คํธ ๋ฐ์ดํฐ์ ๋ํด ์ค์ผ์ผ๋ฌ๋ฅผ ํ์ต์ํค๋ ๋ฐ์ดํฐ ๋์ถ(data leakage)์ ๋ฐฉ์งํฉ๋๋ค. ๋ฉด์ ๊ด์ ์ด ๋ถ๋ถ์ ๋ช ์์ ์ผ๋ก ๊ฒ์ฆํฉ๋๋ค. ๋ถํ ์ ์ ์ ์ฒด ๋ฐ์ดํฐ์ ์ fit_transform์ ์ ์ฉํ๋ ๊ฒ์ ์๋์ด๊ธ ๋ฉด์ ์์ ํ๋ฝ ์์ธ์ด ๋ ์ ์๋ ์น๋ช ์ ์ธ ์ค์์ ๋๋ค.
Data Science & ML ๋ฉด์ ์ค๋น๊ฐ ๋์ จ๋์?
์ธํฐ๋ํฐ๋ธ ์๋ฎฌ๋ ์ดํฐ, flashcards, ๊ธฐ์ ํ ์คํธ๋ก ์ฐ์ตํ์ธ์.
๊ฒฐ๋ก
๋จธ์ ๋ฌ๋ ์๊ณ ๋ฆฌ์ฆ ๋ฉด์ ์ค๋น์์ ๊ฐ์ฅ ์ค์ํ ํต์ฌ ์ฌํญ์ ์ ๋ฆฌํฉ๋๋ค.
- ์ ํ ๋ชจ๋ธ(์ ํ ํ๊ท, ๋ก์ง์คํฑ ํ๊ท)์ ๋ชจ๋ ๊ฒ์ ๊ธฐ์ด์ ๋๋ค. ๊ฐ์ ์กฐ๊ฑด, ๋น์ฉ ํจ์, ๋ชจ๋ธ์ด ์คํจํ๋ ์ํฉ์ ๋ณต์กํ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ๋์ด๊ฐ๊ธฐ ์ ์ ์๋ฒฝํ ์ดํดํด์ผ ํฉ๋๋ค.
- ์์ฌ๊ฒฐ์ ํธ๋ฆฌ๋ ๋จ๋ ์ผ๋ก ์ฌ์ฉํ๋ฉด ๊ณผ์ ํฉ์ด ๋ฐ์ํฉ๋๋ค. ๋๋ค ํฌ๋ ์คํธ(๋ฐฐ๊น )์ ๊ทธ๋๋์ธํธ ๋ถ์คํ (๋ถ์คํ )์ด ์ด๋ฅผ ํด๊ฒฐํ๋ฉฐ, ๊ฐ๊ฐ ์๋ก ๋ค๋ฅธ ํธ๋ ์ด๋์คํ ํน์ฑ์ ๊ฐ์ง๋๋ค.
- K-Means์ PCA๋ ๋น์ง๋ํ์ต์ ๊ธฐ๋ณธ์ด์ง๋ง, ๋ฐ๋์ ํน์ฑ ์ค์ผ์ผ๋ง์ ๋จผ์ ์ํํ๊ณ ๊ฐ ๋ฐฉ๋ฒ์ ํ๊ณ๋ฅผ ์ ํํ ํ์ ํด์ผ ํฉ๋๋ค.
- ํ๊ฐ ์งํ๋ ๋น์ฆ๋์ค ๋ฌธ์ ์ ๋ง๊ฒ ์ ํํด์ผ ํฉ๋๋ค. ๋ถ๊ท ํ ๋ฐ์ดํฐ์์ ์ ํ๋๋ง์ผ๋ก๋ ์๋ฏธ๊ฐ ์์ผ๋ฉฐ, ์ ๋ฐ๋, ์ฌํ์จ, F1, AUC-ROC๋ ๊ฐ๊ฐ ๋ค๋ฅธ ๋ชฉ์ ์ ๋ถํฉํฉ๋๋ค.
- ์ ๊ทํ(Ridge, Lasso, Elastic Net)๋ ๊ณผ์ ํฉ์ ์ ์ดํ์ง๋ง, ํ์ดํ๋ผ์ธ ๋ด์์ ํ์คํ๋ ํน์ฑ์ ์ ์ฉํด์ผ๋ง ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํฉ๋๋ค.
- 2026๋ ๋ฉด์ ์์์ ์ฑ๊ณต์ ๋จ์ํ ๊ตฌํ ๋ฅ๋ ฅ์ด ์๋๋ผ ์๊ณ ๋ฆฌ์ฆ ์ ํ์ ๋ํ ํ๋จ๋ ฅ์ ๋ณด์ฌ์ฃผ๋ ๊ฒ์ ๋ฌ๋ ค ์์ต๋๋ค. ๋ชจ๋ ์ ํ์ "์"๋ฅผ ์ค๋ช ํ ์ ์์ด์ผ ํฉ๋๋ค.
์ฐ์ต์ ์์ํ์ธ์!
๋ฉด์ ์๋ฎฌ๋ ์ดํฐ์ ๊ธฐ์ ํ ์คํธ๋ก ์ง์์ ํ ์คํธํ์ธ์.
Data Science & ML ์ฝ๋์ ๋ฒ๊ทธ๋ฅผ ์ฐพ์ ์ ์๋์
์ค์ ์ฝ๋ ํ ์กฐ๊ฐ, ์จ์ ๋ฒ๊ทธ ํ๋, ํ๋ฃจ ํ ๋ฒ. ๊ณ์ ์์ด ๋ฐ๋ก ๋์ ํ ์ ์์ต๋๋ค.

์์ฑ์
Anthony Fillion-MailletSharpSkill ์ฐฝ์ ์
10๋ ์ด์ ํ์คํ ๊ฐ๋ฐ์ ํด์์ต๋๋ค. SharpSkill์ ์ด์ํ๋ฉฐ ์ด๊ณณ์ ๊ฒ์๋๋ ๋ชจ๋ ๋ด์ฉ์ ์ฑ ์์ ์ง๋๋ค.
2026๋ 4์ 6์ผ ์ ๋ฐ์ดํธ
ํ๊ทธ
๊ณต์
๊ด๋ จ ๊ธฐ์ฌ

2026๋ Python ๋ฐ์ดํฐ ์ฌ์ด์ธ์ค: NumPy, Pandas, Scikit-Learn ์๋ฒฝ ๊ฐ์ด๋
2026๋ ๊ธฐ์ค Python ๋ฐ์ดํฐ ์ฌ์ด์ธ์ค ํต์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ NumPy, Pandas, Scikit-Learn์ ์ค์ ํ์ฉ๋ฒ์ ์ฝ๋ ์์ ์ ํจ๊ป ์์ธํ ๋ค๋ฃน๋๋ค.

2026๋ ๋ฐ์ดํฐ ์ฌ์ด์ธ์ค ๋ฉด์ ์ง๋ฌธ 25์
ํต๊ณ, ๋จธ์ ๋ฌ๋, ํผ์ฒ ์์ง๋์ด๋ง, ๋ฅ๋ฌ๋, SQL, ์์คํ ์ค๊ณ๋ฅผ ๋ง๋ผํ๋ ๋ฐ์ดํฐ ์ฌ์ด์ธ์ค ๋ฉด์ ์ง๋ฌธ 25์ โ Python ์ฝ๋ ์์ ์ ์ฌ์ธต ํด์ค ํฌํจ.

2026๋ MLOps: MLflow, ๋ชจ๋ธ ๋ ์ง์คํธ๋ฆฌ์ ๊ธฐ์ ๋ฉด์ ์ง๋ฌธ
ML ๋ผ์ดํ์ฌ์ดํด, MLflow ์คํ ์ถ์ , ๋ชจ๋ธ ๋ ์ง์คํธ๋ฆฌ ์น๊ฒฉ, ๋ฐฐํฌ ํจํด, ๋๋ฆฌํํธ ๋ชจ๋ํฐ๋ง, 2026๋ ์ ์ํ ์์คํ ๋์์ธ์ Python ์ฝ๋์ ๋ต๋ณ์ผ๋ก ๋ค๋ฃจ๋ MLOps ๋ฉด์ ์ง๋ฌธ.