머신러닝
면접에서 자주 나오는 머신러닝 질문들
질문 목록
학습 기본
- [ ] Cross Validation은 무엇이고 어떻게 해야하나요?
- [ ] 회귀 / 분류시 알맞은 metric은 무엇일까요?
- [ ] 알고 있는 metric에 대해 설명해주세요
- [ ] 정규화를 왜 해야할까요?
- [ ] Local Minima와 Global Minima에 대해 설명해주세요
- [ ] 좋은 모델의 정의는 무엇일까요?
차원축소
- [ ] 차원의 저주에 대해 설명해주세요
- [ ] dimension reduction기법으로 보통 어떤 것들이 있나요?
- [ ] PCA의 역할들(축소, 압축, 노이즈 제거)을 설명해주세요
- [ ] LSA, LDA, SVD 등의 약자와 관계를 설명할 수 있나요?
정규화
- [ ] L1, L2 정규화에 대해 설명해주세요
개별 알고리즘
- [ ] Markov Chain을 고등학생에게 설명하려면?
- [ ] 텍스트 더미에서 주제를 추출하는 방식은?
- [ ] SVM은 왜 반대로 차원을 확장시키는 방식으로 동작할까요?
- [ ] SVM은 왜 좋을까요?
- [ ] 나이브 베이즈(naive bayes)의 장점을 옹호해보세요
- [ ] Association Rule의 Support, Confidence, Lift에 대해 설명해주세요
- [ ] K-means의 대표적 의미론적 단점은 무엇인가요?
- [ ] 스팸 필터에 로지스틱 리그레션을 많이 사용하는 이유는?
- [ ] OLS(ordinary least squre) regression의 공식은 무엇인가요?
최적화
- [ ] Newton's Method와 Gradient Descent 방법에 대해 알고 있나요?
앙상블
- [ ] XGBoost을 아시나요?
- [ ] 앙상블 방법엔 어떤 것들이 있나요?
- [ ] 50개의 작은 의사결정 나무는 큰 의사결정 나무보다 괜찮을까요?
평가
- [ ] ROC 커브에 대해 설명해주실 수 있으신가요?
실무
- [ ] 서버 100대에서 인공신경망보다 Random Forest를 써야하는 이유는?
- [ ] 머신러닝적 접근방법과 통계적 접근방법의 차이는?
- [ ] feature vector란 무엇일까요?
딥러닝 기초
- [ ] 인공신경망의 일반적인 문제점은 무엇일까요?
- [ ] 딥러닝 혁신의 근간은 무엇이라고 생각하시나요?
답변
Cross Validation은 무엇이고 어떻게 해야하나요?
한 줄 정의
데이터를 여러 부분으로 나눠 학습/검증을 반복하여 모델의 일반화 성능을 평가하는 기법
왜 필요한가?
문제: Train 성능은 좋은데 Test 성능이 나쁨 → 과적합
해결: 여러 번 검증해서 "진짜 성능" 추정
K-Fold Cross Validation
데이터를 K개로 나눔 (예: K=5)
Fold 1: [검증] [학습] [학습] [학습] [학습]
Fold 2: [학습] [검증] [학습] [학습] [학습]
Fold 3: [학습] [학습] [검증] [학습] [학습]
Fold 4: [학습] [학습] [학습] [검증] [학습]
Fold 5: [학습] [학습] [학습] [학습] [검증]
최종 성능 = 5개 검증 점수의 평균
from sklearn.model_selection import cross_val_score, KFold
kfold = KFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(model, X, y, cv=kfold)
print(f"평균: {scores.mean():.3f} (±{scores.std():.3f})")
CV 종류
| 방법 |
특징 |
사용 시점 |
| K-Fold |
가장 일반적 |
대부분 상황 |
| Stratified K-Fold |
클래스 비율 유지 |
불균형 분류 |
| Leave-One-Out |
K=n |
데이터 매우 적을 때 |
| Time Series Split |
시간순 유지 |
시계열 데이터 |
| Group K-Fold |
그룹 단위 분리 |
같은 유저 데이터 분리 필요 시 |
from sklearn.model_selection import StratifiedKFold, TimeSeriesSplit
# 불균형 데이터
skf = StratifiedKFold(n_splits=5)
# 시계열 데이터
tscv = TimeSeriesSplit(n_splits=5)
주의사항
- 데이터 누수 방지: 전처리(스케일링 등)는 각 fold 안에서
- Shuffle: 데이터 순서에 패턴 있으면 shuffle=True
- K 선택: 보통 5 또는 10 (데이터 적으면 큰 K)
면접 포인트
- 일반화 성능 추정이 목적
- K-Fold: K번 학습/검증 → 평균
- Stratified: 클래스 비율 유지
회귀 / 분류시 알맞은 metric은 무엇일까요?
한 줄 정의
회귀: 예측값과 실제값의 차이 | 분류: 예측 클래스의 정확성
회귀 (Regression) Metrics
| Metric |
수식 |
특징 |
| MSE |
Σ(y-ŷ)²/n |
큰 오차에 민감 |
| RMSE |
√MSE |
원래 단위로 해석 |
| MAE |
Σ|y-ŷ|/n |
이상치에 덜 민감 |
| MAPE |
Σ|y-ŷ|/y × 100 |
상대적 오차 (%) |
| R² |
1 - SS_res/SS_tot |
설명력 (0~1) |
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
mse = mean_squared_error(y_true, y_pred)
mae = mean_absolute_error(y_true, y_pred)
r2 = r2_score(y_true, y_pred)
분류 (Classification) Metrics
| Metric |
수식 |
언제 사용 |
| Accuracy |
(TP+TN)/전체 |
균형 데이터 |
| Precision |
TP/(TP+FP) |
FP 비용 클 때 (스팸) |
| Recall |
TP/(TP+FN) |
FN 비용 클 때 (암 진단) |
| F1 |
2×P×R/(P+R) |
P와 R 균형 |
| AUC-ROC |
곡선 아래 면적 |
임계값 무관 비교 |
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
accuracy = accuracy_score(y_true, y_pred)
precision = precision_score(y_true, y_pred)
recall = recall_score(y_true, y_pred)
f1 = f1_score(y_true, y_pred)
상황별 선택
| 상황 |
권장 Metric |
| 균형 분류 |
Accuracy, F1 |
| 불균형 분류 |
F1, AUC-ROC, Precision/Recall |
| 이상치 있는 회귀 |
MAE |
| 비즈니스 보고 |
MAPE (해석 쉬움) |
| 모델 비교 |
R², AUC |
면접 포인트
- 불균형 데이터에서 Accuracy는 의미 없음
- Precision vs Recall: 비용 기준으로 선택
- 회귀에서 이상치 있으면 MAE
알고 있는 metric에 대해 설명해주세요
Confusion Matrix 기반
Predicted
Pos Neg
Actual Pos [ TP | FN ]
Neg [ FP | TN ]
| Metric |
계산 |
의미 |
| Accuracy |
(TP+TN)/(TP+TN+FP+FN) |
전체 정확도 |
| Precision |
TP/(TP+FP) |
양성 예측 중 실제 양성 |
| Recall (Sensitivity) |
TP/(TP+FN) |
실제 양성 중 맞춘 비율 |
| Specificity |
TN/(TN+FP) |
실제 음성 중 맞춘 비율 |
| F1 Score |
2PR/(P+R) |
Precision과 Recall의 조화평균 |
ROC-AUC
ROC Curve: FPR(x축) vs TPR(y축)
- FPR = FP/(FP+TN)
- TPR = TP/(TP+FN) = Recall
AUC = ROC 곡선 아래 면적 (0.5~1.0)
- 0.5: 랜덤 예측
- 1.0: 완벽한 분류
from sklearn.metrics import roc_auc_score, roc_curve
auc = roc_auc_score(y_true, y_prob)
fpr, tpr, thresholds = roc_curve(y_true, y_prob)
회귀 Metrics 상세
| Metric |
특징 |
| MSE |
제곱 → 큰 오차 강하게 패널티 |
| RMSE |
MSE의 제곱근, 원래 단위 |
| MAE |
절대값 → 이상치에 강건 |
| MAPE |
퍼센트 → 해석 쉬움 (0일 때 문제) |
| R² |
1이면 완벽, 음수 가능 (평균보다 못함) |
Log Loss (Cross-Entropy)
LogLoss = -Σ[y×log(p) + (1-y)×log(1-p)] / n
- 확률 예측의 품질 측정
- 확신 있게 틀리면 큰 패널티
다중 클래스
| 방식 |
설명 |
| Macro |
클래스별 평균 (균등 가중) |
| Micro |
전체 TP/FP/FN으로 계산 |
| Weighted |
클래스 크기로 가중 평균 |
f1_score(y_true, y_pred, average='macro') # 불균형 시 권장
면접 포인트
- Confusion Matrix의 TP/FP/FN/TN 설명
- AUC는 임계값 무관하게 모델 비교 가능
- 다중 클래스에서 macro vs micro 차이
정규화를 왜 해야할까요?
한 줄 정의
피처들의 스케일을 맞춰 학습 안정성과 수렴 속도를 높이는 전처리
왜 필요한가?
문제 상황:
- 키: 150~200 (cm)
- 연봉: 3000~10000 (만원)
→ 연봉이 수치적으로 크므로 모델이 연봉에 과도하게 민감
→ Gradient Descent에서 지그재그 현상 발생
정규화 방법
| 방법 |
수식 |
결과 범위 |
특징 |
| Min-Max |
(x-min)/(max-min) |
[0, 1] |
이상치에 민감 |
| Z-score (Standardization) |
(x-μ)/σ |
평균0, 분산1 |
가장 일반적 |
| Robust |
(x-median)/IQR |
가변 |
이상치에 강건 |
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler
# Z-score 정규화 (가장 많이 사용)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test) # fit은 train에만!
정규화가 필수인 알고리즘
| 필수 |
불필요 |
| Linear Regression |
Decision Tree |
| Logistic Regression |
Random Forest |
| SVM |
XGBoost |
| KNN (거리 기반) |
LightGBM |
| Neural Network |
|
| K-means |
|
주의사항
# ❌ 잘못된 방법 (Data Leakage!)
scaler.fit(전체_데이터)
# ✅ 올바른 방법
scaler.fit(train_데이터)
scaler.transform(test_데이터)
면접 포인트
- 스케일 차이 → 특정 피처에 편향
- Gradient Descent 수렴 속도 개선
- Test에는 fit 하면 안 됨 (data leakage)
Local Minima와 Global Minima에 대해 설명해주세요
한 줄 정의
Global Minima: 전체 공간에서 가장 낮은 점 | Local Minima: 주변에서만 가장 낮은 점
시각적 이해
손실함수 L(θ)
╭─╮
╱ ╲ ╭──╮
╱ ╲ ╱ ╲
╱ ╲╱ ╲
╱ ↑ ↑ ╲____
Local Global
Minima Minima
왜 문제인가?
Gradient Descent는 기울기=0인 곳에서 멈춤
→ Local Minima에 빠지면 Global Minima를 못 찾음
→ 최적이 아닌 해에서 학습 종료
딥러닝에서는?
실제로는 Local Minima가 큰 문제가 아님!
이유:
1. 고차원 공간: 모든 방향에서 동시에 최솟값이 되기 어려움
2. Saddle Point가 더 문제: 어떤 방향은 최소, 어떤 방향은 최대
3. Local Minima도 충분히 좋음: 대부분 Global과 성능 비슷
Saddle Point (안장점):
↗
↙ ↘
↖
한 방향: 최소 / 다른 방향: 최대
탈출 방법
| 방법 |
설명 |
| Momentum |
관성으로 작은 골짜기 통과 |
| Learning Rate Scheduling |
큰 LR → 작은 LR |
| Random Restart |
여러 초기값에서 시작 |
| Stochastic GD |
미니배치 노이즈로 탈출 |
| Adam Optimizer |
적응적 학습률 |
면접 포인트
- Local: 주변에서만 최소 / Global: 전체에서 최소
- 딥러닝은 Saddle Point가 더 큰 문제
- Momentum, SGD로 탈출 가능
좋은 모델의 정의는 무엇일까요?
한 줄 정의
본 적 없는 데이터에서도 좋은 성능을 내는, 일반화된 모델
좋은 모델의 조건
1. 일반화 (Generalization)
Train 성능 ≈ Test 성능
2. 적절한 복잡도
과적합(Overfitting) ❌
과소적합(Underfitting) ❌
3. 비즈니스 목표 달성
정확도 99%여도 실무에서 못 쓰면 ❌
Bias-Variance Tradeoff
Total Error = Bias² + Variance + Irreducible Noise
모델 복잡도 →
↑
Error │ Bias
│ ↘
│ ↘_____
│ ↗ Variance
│ ____↗
│────────●──────────
│ Sweet Spot
└──────────────────────→
| 상태 |
Bias |
Variance |
해결책 |
| Underfitting |
높음 |
낮음 |
모델 복잡도 ↑, 피처 추가 |
| Overfitting |
낮음 |
높음 |
정규화, 데이터 ↑, Dropout |
| Good Fit |
적당 |
적당 |
유지 |
실무 관점의 "좋은 모델"
| 기준 |
설명 |
| 성능 |
Metric 기준 충족 |
| 해석 가능성 |
왜 그런 예측인지 설명 가능 |
| 추론 속도 |
서비스 지연 시간 내 응답 |
| 학습 비용 |
합리적인 리소스로 학습 가능 |
| 유지보수 |
재학습, 모니터링 용이 |
# 좋은 모델 = 일반화 성능 확인
from sklearn.model_selection import cross_val_score
scores = cross_val_score(model, X, y, cv=5)
print(f"평균: {scores.mean():.3f}, 표준편차: {scores.std():.3f}")
# 표준편차가 작아야 안정적인 모델
면접 포인트
- 일반화: 본 적 없는 데이터에서의 성능
- Bias-Variance Tradeoff 이해
- 실무: 성능 + 해석 + 속도 + 비용
차원의 저주에 대해 설명해주세요
한 줄 정의
차원이 높아질수록 데이터가 희소(sparse)해져서 학습이 어려워지는 현상
왜 발생하는가?
1차원: ●●●●●●●●●● (밀집)
2차원: ● ● ●
● ●
● ● (분산됨)
3차원: ... (더 분산)
같은 10개의 점이라도
→ 차원이 높아질수록 점들 사이 거리가 멀어짐
→ "가까운 이웃" 개념이 무의미해짐
수학적 직관
단위 초구(hypersphere)의 부피 비율
차원 d가 증가하면:
- 데이터가 주로 경계(boundary) 근처에 분포
- 중심 근처는 거의 비어있음
필요 데이터 수 ∝ exp(d)
→ 차원이 1 증가할 때마다 필요 데이터 기하급수적 증가
KNN에서의 문제
# 고차원에서 KNN이 망가지는 이유
# 모든 점들 사이의 거리가 비슷해짐
import numpy as np
# 차원별 거리 비교
for d in [2, 10, 100, 1000]:
X = np.random.randn(100, d)
distances = np.linalg.norm(X[0] - X[1:], axis=1)
print(f"d={d}: max/min = {distances.max()/distances.min():.2f}")
# 고차원일수록 max/min → 1 (거리 구분 안 됨)
해결책
| 방법 |
설명 |
| PCA |
분산 큰 축으로 차원 축소 |
| Feature Selection |
중요한 피처만 선택 |
| L1 Regularization |
불필요 피처 가중치 0으로 |
| t-SNE, UMAP |
비선형 차원 축소 (시각화용) |
| 데이터 추가 |
차원에 비례한 데이터 확보 |
면접 포인트
- 고차원 → 데이터 희소 → 거리 개념 무의미
- KNN, 클러스터링 등 거리 기반 알고리즘에 치명적
- 해결: 차원 축소 (PCA, Feature Selection)
dimension reduction기법으로 보통 어떤 것들이 있나요?
한 줄 정의
고차원 데이터를 정보 손실 최소화하며 저차원으로 변환하는 기법
주요 기법 분류
차원 축소
├── 선형 (Linear)
│ ├── PCA (Principal Component Analysis)
│ ├── LDA (Linear Discriminant Analysis)
│ └── SVD (Singular Value Decomposition)
│
└── 비선형 (Non-linear)
├── t-SNE
├── UMAP
├── Autoencoder
└── Kernel PCA
기법별 특징
| 기법 |
원리 |
용도 |
| PCA |
분산 최대화 축 찾기 |
전처리, 노이즈 제거 |
| LDA |
클래스 분리 최대화 |
분류 전처리 |
| t-SNE |
확률 분포 유지 |
2D/3D 시각화 |
| UMAP |
위상 구조 유지 |
시각화, 클러스터링 |
| Autoencoder |
인코더-디코더 학습 |
특징 추출, 생성 |
코드 예시
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
import umap
# PCA - 전처리용
pca = PCA(n_components=50)
X_pca = pca.fit_transform(X)
print(f"설명 분산: {pca.explained_variance_ratio_.sum():.2%}")
# t-SNE - 시각화용 (2D)
tsne = TSNE(n_components=2, perplexity=30)
X_tsne = tsne.fit_transform(X)
# UMAP - 시각화 + 학습용
reducer = umap.UMAP(n_components=2)
X_umap = reducer.fit_transform(X)
선택 기준
| 목적 |
추천 기법 |
| ML 파이프라인 전처리 |
PCA |
| 분류 성능 향상 |
LDA |
| 고차원 데이터 시각화 |
t-SNE, UMAP |
| 딥러닝 특징 추출 |
Autoencoder |
면접 포인트
- PCA: 분산 최대화, 선형, 학습 가능
- t-SNE/UMAP: 비선형, 시각화용 (학습에 부적합)
- 선형 vs 비선형 차이 설명 가능해야 함
PCA의 역할들(축소, 압축, 노이즈 제거)을 설명해주세요
한 줄 정의
분산 최대화 방향의 주성분을 찾아 차원 축소/압축/노이즈 제거를 수행
PCA 원리
원본 데이터 (2D) PCA 변환
● ● ●●●●●●●●●
● ● ● → (PC1 방향으로 투영)
● ●
PC1: 분산이 가장 큰 방향
PC2: PC1에 직교하며 그 다음으로 분산 큰 방향
1. 차원 축소 (Dimensionality Reduction)
from sklearn.decomposition import PCA
# 100차원 → 10차원
pca = PCA(n_components=10)
X_reduced = pca.fit_transform(X)
# 또는 분산 비율로 지정 (95% 보존)
pca = PCA(n_components=0.95)
X_reduced = pca.fit_transform(X)
print(f"선택된 차원: {pca.n_components_}")
용도: 고차원 데이터 전처리, 학습 속도 향상, 과적합 방지
2. 데이터 압축 (Compression)
# 이미지 압축 예시 (28x28=784 → 50)
pca = PCA(n_components=50)
X_compressed = pca.fit_transform(X_images)
# 복원
X_reconstructed = pca.inverse_transform(X_compressed)
# 압축률: 784 → 50 (약 6% 용량)
용도: 저장 공간 절약, 전송 효율화
3. 노이즈 제거 (Denoising)
원리:
- 노이즈는 보통 분산이 작은 성분에 포함
- 주요 PC만 남기면 노이즈 제거됨
원본 + 노이즈 → PCA (상위 PC만) → 복원 → 깨끗한 데이터
# 노이즈 제거
pca = PCA(n_components=0.9) # 분산 90%만 보존
X_denoised = pca.inverse_transform(pca.fit_transform(X_noisy))
면접 포인트
- 축소: 고차원 → 저차원 (분산 보존)
- 압축: inverse_transform으로 복원 가능
- 노이즈 제거: 분산 작은 성분 = 노이즈
LSA, LDA, SVD 등의 약자와 관계를 설명할 수 있나요?
약자 정리
| 약자 |
풀네임 |
분야 |
| SVD |
Singular Value Decomposition |
선형대수 (행렬 분해) |
| PCA |
Principal Component Analysis |
차원 축소 |
| LSA |
Latent Semantic Analysis |
NLP (토픽 모델링) |
| LDA (1) |
Linear Discriminant Analysis |
차원 축소 (지도학습) |
| LDA (2) |
Latent Dirichlet Allocation |
NLP (토픽 모델링) |
관계도
SVD (기반 기술)
│
├── PCA: 공분산 행렬에 SVD 적용
│
└── LSA: 문서-단어 행렬에 SVD 적용
(= Truncated SVD)
LDA (Linear Discriminant Analysis)
└── 클래스 간 분산 / 클래스 내 분산 최대화
LDA (Latent Dirichlet Allocation)
└── 확률적 토픽 모델 (SVD와 무관)
SVD와 PCA 관계
# SVD: A = U Σ V^T
# PCA는 내부적으로 SVD 사용
from sklearn.decomposition import PCA, TruncatedSVD
# 동일한 결과 (중심화 차이 있음)
pca = PCA(n_components=10)
svd = TruncatedSVD(n_components=10)
LSA (Latent Semantic Analysis)
from sklearn.decomposition import TruncatedSVD
from sklearn.feature_extraction.text import TfidfVectorizer
# 문서-단어 행렬
tfidf = TfidfVectorizer()
X = tfidf.fit_transform(documents)
# LSA = TruncatedSVD (문서-단어 행렬에 적용)
lsa = TruncatedSVD(n_components=100)
X_topics = lsa.fit_transform(X)
LDA 두 가지 구분
|
Linear Discriminant Analysis |
Latent Dirichlet Allocation |
| 분야 |
차원 축소 |
NLP 토픽 모델 |
| 학습 |
지도학습 (레이블 필요) |
비지도학습 |
| 목적 |
분류 전처리 |
토픽 추출 |
# LDA (차원 축소)
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
lda = LinearDiscriminantAnalysis(n_components=2)
X_lda = lda.fit_transform(X, y) # y 필요 (지도학습)
# LDA (토픽 모델)
from sklearn.decomposition import LatentDirichletAllocation
lda = LatentDirichletAllocation(n_components=10)
X_topics = lda.fit_transform(X) # 비지도
면접 포인트
- SVD가 기반 기술, PCA와 LSA가 이를 활용
- LDA 두 개 구분: 차원축소 vs 토픽모델
- LSA = TruncatedSVD (NLP 맥락)
L1, L2 정규화에 대해 설명해주세요
한 줄 정의
손실 함수에 가중치 패널티를 추가하여 과적합을 방지하는 기법
수식 비교
원본 Loss: L(θ)
L1 (Lasso): L(θ) + λ Σ|θᵢ|
L2 (Ridge): L(θ) + λ Σθᵢ²
λ: 정규화 강도 (하이퍼파라미터)
핵심 차이
|
L1 (Lasso) |
L2 (Ridge) |
| 패널티 |
절대값 합 |
제곱 합 |
| 효과 |
일부 가중치 → 0 |
가중치 작아짐 |
| 결과 |
Sparse (희소) |
Dense (균등 축소) |
| 용도 |
Feature Selection |
과적합 방지 |
기하학적 이해
L1: 마름모 제약 L2: 원형 제약
◇ ○
↗ ↘ ↗ ↘
↑ ● ↓ 최적점이 ↑ ● ↓ 최적점이
↖ ↙ 꼭짓점(축)에 ↖ ↙ 원 위에
◇ → 가중치=0 ○ → 가중치 작음
● = 원래 최적점
코드 예시
from sklearn.linear_model import Lasso, Ridge, ElasticNet
# L1 (Lasso) - 피처 선택
lasso = Lasso(alpha=0.1)
lasso.fit(X_train, y_train)
print(f"0인 가중치: {(lasso.coef_ == 0).sum()}")
# L2 (Ridge) - 과적합 방지
ridge = Ridge(alpha=1.0)
ridge.fit(X_train, y_train)
# Elastic Net - L1 + L2 결합
elastic = ElasticNet(alpha=0.1, l1_ratio=0.5) # 0.5 = L1:L2 반반
언제 무엇을 쓸까?
| 상황 |
선택 |
| 피처가 많고 일부만 중요 |
L1 (Lasso) |
| 다중공선성 있음 |
L2 (Ridge) |
| 피처 선택 + 안정성 |
Elastic Net |
| 딥러닝 과적합 |
L2 (Weight Decay) |
면접 포인트
- L1: Sparse → Feature Selection
- L2: 가중치 작게 → 과적합 방지
- 기하학적 해석: 제약 조건 형태 차이
Markov Chain을 고등학생에게 설명하려면?
한 줄 정의
현재 상태만으로 다음 상태가 결정되는 확률 과정
고등학생 설명
날씨 예측 게임!
오늘 맑음 → 내일 날씨는?
- 맑음: 70%
- 비: 30%
핵심: 어제 날씨는 상관없음!
"오늘"만 보고 "내일" 예측
이것이 마르코프 성질:
"과거는 잊고, 현재만 봐!"
시각적 예시
0.7
┌─────────┐
│ ↓ │
▼ │
[맑음] ────────→ [비]
↑ 0.3 │
│ │
└─────────────┘
0.4 0.6 (비→비)
전이 확률 행렬 P:
맑음 비
맑음 [0.7 0.3]
비 [0.4 0.6]
왜 유용한가?
1. 단순함: 전체 이력 대신 현재만 기억
2. 계산 가능: 행렬 곱으로 n일 후 예측
P² = 2일 후 확률
P^n = n일 후 확률
실생활 예시
| 분야 |
예시 |
| 검색엔진 |
PageRank (웹페이지 이동) |
| 자연어 |
다음 단어 예측 |
| 금융 |
신용등급 변화 |
| 게임 |
상태 기반 AI |
import numpy as np
# 전이 행렬
P = np.array([[0.7, 0.3], # 맑음 → 맑음/비
[0.4, 0.6]]) # 비 → 맑음/비
# 3일 후 확률
P_3days = np.linalg.matrix_power(P, 3)
print(P_3days)
면접 포인트
- 마르코프 성질: 현재만으로 미래 결정
- 전이 행렬: 상태 간 이동 확률
- 응용: PageRank, 언어 모델
텍스트 더미에서 주제를 추출하는 방식은?
한 줄 정의
토픽 모델링: 문서 집합에서 숨겨진 주제(토픽)를 자동으로 발견하는 기법
주요 방법
| 방법 |
원리 |
특징 |
| LDA |
확률적 생성 모델 |
가장 대표적, 해석 용이 |
| LSA |
SVD 기반 |
빠름, 수학적 단순 |
| NMF |
비음수 행렬 분해 |
희소 표현, 해석 용이 |
| BERTopic |
BERT + 클러스터링 |
최신, 고품질 |
LDA (Latent Dirichlet Allocation)
문서 = 토픽들의 혼합
토픽 = 단어들의 확률 분포
문서1: 토픽A(60%) + 토픽B(40%)
토픽A: "경제", "주식", "금리" 높은 확률
토픽B: "정치", "선거", "투표" 높은 확률
from sklearn.decomposition import LatentDirichletAllocation
from sklearn.feature_extraction.text import CountVectorizer
# 문서-단어 행렬
vectorizer = CountVectorizer(max_features=1000, stop_words='english')
X = vectorizer.fit_transform(documents)
# LDA
lda = LatentDirichletAllocation(n_components=10, random_state=42)
lda.fit(X)
# 각 토픽의 상위 단어 출력
feature_names = vectorizer.get_feature_names_out()
for topic_idx, topic in enumerate(lda.components_):
top_words = [feature_names[i] for i in topic.argsort()[:-10:-1]]
print(f"토픽 {topic_idx}: {', '.join(top_words)}")
BERTopic (최신)
from bertopic import BERTopic
# 간단한 사용법
topic_model = BERTopic(language="korean")
topics, probs = topic_model.fit_transform(documents)
# 토픽 확인
topic_model.get_topic_info()
선택 가이드
| 상황 |
추천 |
| 빠른 프로토타입 |
LSA, NMF |
| 해석 가능성 중요 |
LDA |
| 고품질 필요 |
BERTopic |
| 한국어 |
BERTopic (다국어 지원) |
면접 포인트
- LDA: 문서=토픽 혼합, 토픽=단어 분포
- LSA vs LDA: 행렬분해 vs 확률모델
- 최신 트렌드: BERTopic (BERT 임베딩 활용)
SVM은 왜 반대로 차원을 확장시키는 방식으로 동작할까요?
한 줄 정의
저차원에서 선형 분리 불가능한 데이터를 고차원에서 선형 분리 가능하게 만들기 위해
핵심 아이디어
2D에서 분리 불가능: 3D로 올리면 분리 가능:
↑ z
○ ○ ○ │ ○ ○ ○
○ ● ● ● ○ → │ ● ● ● (평면으로 분리!)
○ ○ ○ │ ○ ○ ○
└────────→ x,y
φ(x) = (x₁, x₂, x₁²+x₂²) ← 차원 확장 함수
Kernel Trick
문제: 고차원 계산 비용이 너무 큼
해결: Kernel Trick!
- 고차원에서 내적 = 저차원에서 커널 함수 계산
- φ(x)·φ(y) = K(x, y)
실제로 고차원으로 변환하지 않고
고차원에서의 효과를 얻음!
주요 커널
| 커널 |
수식 |
특징 |
| Linear |
x·y |
선형 분리 가능할 때 |
| Polynomial |
(x·y + c)^d |
다항식 경계 |
| RBF (Gaussian) |
exp(-γ|x-y|²) |
무한 차원, 가장 많이 사용 |
from sklearn.svm import SVC
# RBF 커널 (기본값) - 무한 차원으로 매핑
svm_rbf = SVC(kernel='rbf', C=1.0, gamma='scale')
# 선형 커널 - 고차원 매핑 없음
svm_linear = SVC(kernel='linear', C=1.0)
# 다항식 커널
svm_poly = SVC(kernel='poly', degree=3)
왜 "반대로"인가?
일반적 접근: 차원의 저주 → 차원 축소
SVM 접근: 선형 분리 불가 → 차원 확장
But! Kernel Trick으로 실제 계산은 저차원
→ 고차원의 이점 + 저차원의 효율성
면접 포인트
- 목적: 선형 분리 불가 → 고차원에서 선형 분리
- Kernel Trick: 실제 변환 없이 고차원 효과
- RBF 커널: 무한 차원, 범용적
SVM은 왜 좋을까요?
한 줄 정의
마진 최대화 + Kernel Trick으로 이론적 기반이 탄탄하고 일반화 성능이 우수
SVM의 장점
| 장점 |
설명 |
| 마진 최대화 |
결정 경계와 데이터 간 거리 최대 → 일반화 ↑ |
| Kernel Trick |
비선형 문제 해결 가능 |
| 고차원에 강함 |
피처 수 > 샘플 수여도 잘 동작 |
| 이론적 기반 |
통계적 학습 이론 (VC dimension) |
| 과적합 저항 |
정규화 파라미터 C로 조절 |
마진 최대화
○ │ ●
○ ○ │ ● ●
○ ← margin → ●
○ ○ │ ● ●
○ │ ●
결정경계
SVM: margin을 최대화하는 결정경계 찾기
→ 새 데이터에 대한 오분류 확률 ↓
언제 SVM을 쓸까?
| 적합 |
부적합 |
| 중소규모 데이터 |
대규모 데이터 (느림) |
| 고차원 데이터 |
노이즈 많은 데이터 |
| 이진 분류 |
확률 추정 필요 시 |
| 텍스트 분류 |
실시간 추론 필요 시 |
한계점
1. 대용량 데이터 → O(n²~n³) 학습 시간
2. 확률 출력 어려움 (Platt scaling 필요)
3. 하이퍼파라미터 튜닝 (C, gamma) 민감
4. 해석 어려움 (블랙박스)
면접 포인트
- 마진 최대화 → 일반화 성능
- Kernel Trick → 비선형 분리
- 대용량에는 부적합 (딥러닝, XGBoost 대체)
나이브 베이즈(naive bayes)의 장점을 옹호해보세요
한 줄 정의
피처 간 조건부 독립 가정으로 계산을 단순화한 확률적 분류기
"Naive"의 의미
Naive (순진한) 가정:
P(x₁, x₂, ... | y) = P(x₁|y) × P(x₂|y) × ...
"피처들이 서로 독립이다"
현실에서는 거의 틀린 가정이지만...
놀랍게도 실전에서 잘 동작함!
장점 (옹호)
| 장점 |
설명 |
| 빠름 |
학습 O(nd), 추론 O(d) |
| 적은 데이터 OK |
각 피처별로 따로 추정 |
| 확률 출력 |
P(y|x) 직접 제공 |
| 고차원 OK |
텍스트 분류에 특히 강점 |
| 해석 가능 |
각 피처의 기여도 확인 가능 |
| 온라인 학습 |
새 데이터 추가 쉬움 |
왜 잘 동작하나?
1. 분류에서는 P(y|x) 순위만 중요
→ 확률의 절대값이 틀려도 순위가 맞으면 OK
2. 추정 오차가 서로 상쇄
→ 과대추정 + 과소추정 ≈ 평균
3. 고차원에서 복잡한 모델보다 안정적
→ Bias ↑ but Variance ↓
대표 사용 사례
from sklearn.naive_bayes import MultinomialNB
# 스팸 필터 (텍스트 분류의 클래식)
spam_classifier = MultinomialNB()
spam_classifier.fit(X_tfidf, y_labels)
# 감성 분석, 문서 분류 등
| 사용 사례 |
이유 |
| 스팸 필터 |
빠름, 새 스팸 패턴 빠른 적응 |
| 문서 분류 |
고차원 텍스트에 강함 |
| 실시간 분류 |
추론 속도 빠름 |
| 베이스라인 |
빠르게 성능 기준점 확보 |
면접 포인트
- Naive 가정 틀려도 실전에서 잘 동작
- 빠름 + 적은 데이터 + 확률 출력
- 텍스트 분류의 강력한 베이스라인
Association Rule의 Support, Confidence, Lift에 대해 설명해주세요
한 줄 정의
장바구니 분석에서 아이템 간 연관성을 측정하는 세 가지 지표
예시 상황
규칙: {맥주} → {기저귀}
"맥주를 사면 기저귀도 산다"
전체 거래: 1000건
맥주 구매: 200건
기저귀 구매: 300건
맥주+기저귀 동시 구매: 100건
세 가지 지표
| 지표 |
수식 |
의미 |
예시 값 |
| Support |
P(A∩B) |
동시 발생 빈도 |
100/1000 = 10% |
| Confidence |
P(B|A) |
A 샀을 때 B 살 확률 |
100/200 = 50% |
| Lift |
P(B|A)/P(B) |
연관성 강도 |
0.5/0.3 = 1.67 |
각 지표 해석
Support = 10%
→ 전체 거래 중 10%가 맥주+기저귀 동시 구매
→ 너무 낮으면 희귀한 규칙 (신뢰도 ↓)
Confidence = 50%
→ 맥주 산 사람 중 50%가 기저귀도 구매
→ 마케팅 타겟팅에 유용
Lift = 1.67
→ 맥주 구매가 기저귀 구매를 1.67배 증가시킴
→ 1보다 크면 양의 연관, 1이면 무관, 1 미만이면 음의 연관
Lift 해석
Lift > 1: 양의 연관 (A→B 촉진)
Lift = 1: 독립 (연관 없음)
Lift < 1: 음의 연관 (A→B 억제)
코드 예시
from mlxtend.frequent_patterns import apriori, association_rules
# Apriori로 빈발 아이템셋 찾기
frequent_items = apriori(df, min_support=0.05, use_colnames=True)
# 연관 규칙 생성
rules = association_rules(frequent_items, metric="lift", min_threshold=1.0)
# Support, Confidence, Lift 확인
print(rules[['antecedents', 'consequents', 'support', 'confidence', 'lift']])
면접 포인트
- Support: 얼마나 자주 (빈도)
- Confidence: 얼마나 확실히 (조건부 확률)
- Lift: 얼마나 의미있게 (독립 대비 증가율)
K-means의 대표적 의미론적 단점은 무엇인가요?
한 줄 정의
구형(spherical) 클러스터 가정과 K 사전 지정 등의 제약
주요 단점
| 단점 |
설명 |
| K 사전 지정 |
클러스터 수를 미리 알아야 함 |
| 구형 클러스터 가정 |
비구형 클러스터 못 찾음 |
| 크기 균등 가정 |
크기 다른 클러스터에 약함 |
| 초기값 민감 |
초기 중심점에 따라 결과 달라짐 |
| 이상치 민감 |
평균 기반이라 이상치 영향 큼 |
구형 클러스터 문제
K-means가 잘 되는 경우: K-means가 실패하는 경우:
●●● ○○○ ●●●●●●●●●●●●●
●●● ○○○ ○○○○○○○○○○○○○
●●● ○○○ (선형 클러스터)
(구형 클러스터) ●●●
● ●
○○○○○ ●
● ●
●●●
(동심원 클러스터)
대안
| 문제 |
대안 알고리즘 |
| K 모름 |
DBSCAN, Mean Shift |
| 비구형 |
DBSCAN, Spectral Clustering |
| 크기 다름 |
DBSCAN, GMM |
| 이상치 |
K-medoids, DBSCAN |
from sklearn.cluster import KMeans, DBSCAN
# K-means: K 필요
kmeans = KMeans(n_clusters=3)
# DBSCAN: K 불필요, 비구형 OK
dbscan = DBSCAN(eps=0.5, min_samples=5)
"의미론적" 단점
K-means는 "의미 있는" 그룹을 찾는 게 아니라
"거리가 가까운" 그룹을 찾음
예: 고객 세그먼트
- K-means: 숫자적으로 가까운 고객 그룹
- 원하는 것: 비즈니스 의미 있는 고객 그룹
→ 해석이 어렵고 비즈니스 의미 없을 수 있음
면접 포인트
- K 사전 지정 필요
- 구형 클러스터 가정 (비구형 실패)
- 의미론적: 거리 기반 ≠ 비즈니스 의미
스팸 필터에 로지스틱 리그레션을 많이 사용하는 이유는?
한 줄 정의
확률 출력, 해석 가능성, 빠른 학습이 스팸 필터 요구사항과 일치
스팸 필터 요구사항 vs 로지스틱 회귀
| 요구사항 |
로지스틱 회귀가 적합한 이유 |
| 확률 필요 |
0~1 확률 출력 (임계값 조절 가능) |
| 빠른 추론 |
선형 연산만 → 실시간 처리 |
| 해석 필요 |
어떤 단어가 스팸 판단에 기여했는지 |
| 업데이트 |
새 스팸 패턴에 빠른 재학습 |
| 고차원 |
TF-IDF 희소 벡터 처리 가능 |
확률 기반 임계값 조절
from sklearn.linear_model import LogisticRegression
model = LogisticRegression()
model.fit(X_train, y_train)
# 확률 출력
proba = model.predict_proba(X_test)[:, 1]
# 임계값 조절로 FP/FN 트레이드오프 제어
# 정상 메일 스팸 처리 방지 (높은 임계값)
y_pred = (proba > 0.9).astype(int)
# 스팸 놓침 방지 (낮은 임계값)
y_pred = (proba > 0.5).astype(int)
해석 가능성
# 스팸/햄 판단 근거 확인
feature_names = vectorizer.get_feature_names_out()
coef = model.coef_[0]
# 스팸 키워드 (가중치 높음)
spam_keywords = [(feature_names[i], coef[i])
for i in coef.argsort()[-10:]]
# ['무료', '당첨', '클릭', '지금바로', ...]
# 정상 키워드 (가중치 낮음/음수)
ham_keywords = [(feature_names[i], coef[i])
for i in coef.argsort()[:10]]
다른 알고리즘과 비교
| 알고리즘 |
확률 |
해석 |
속도 |
스팸 필터 적합성 |
| Logistic Regression |
✅ |
✅ |
✅ |
⭐⭐⭐ |
| Naive Bayes |
✅ |
✅ |
✅ |
⭐⭐⭐ |
| SVM |
△ |
❌ |
○ |
⭐⭐ |
| Random Forest |
✅ |
△ |
△ |
⭐⭐ |
| 딥러닝 |
✅ |
❌ |
❌ |
⭐ |
면접 포인트
- 확률 출력 → 임계값 조절 (FP/FN 트레이드오프)
- 해석 가능 → 어떤 단어가 스팸 판단에 기여
- 빠름 → 실시간 이메일 처리
OLS(ordinary least square) regression의 공식은 무엇인가요?
한 줄 정의
잔차 제곱합(RSS)을 최소화하는 회귀 계수를 찾는 방법
수식
목표: RSS = Σ(yᵢ - ŷᵢ)² = Σ(yᵢ - Xᵢβ)² 최소화
해 (Closed-form solution):
β = (X^T X)^(-1) X^T y
여기서:
- X: 설계 행렬 (n × p)
- y: 타겟 벡터 (n × 1)
- β: 회귀 계수 (p × 1)
유도 과정
RSS = (y - Xβ)^T (y - Xβ)
∂RSS/∂β = -2X^T(y - Xβ) = 0
X^T y = X^T Xβ
β = (X^T X)^(-1) X^T y
코드 구현
import numpy as np
# numpy로 OLS 직접 구현
def ols_closed_form(X, y):
"""OLS closed-form solution"""
# β = (X^T X)^(-1) X^T y
return np.linalg.inv(X.T @ X) @ X.T @ y
# sklearn 사용
from sklearn.linear_model import LinearRegression
model = LinearRegression()
model.fit(X, y)
# model.coef_ 가 β (계수)
OLS 가정
| 가정 |
위반 시 문제 |
| 선형성 |
비선형 관계 못 잡음 |
| 독립성 |
계수 추정 편향 |
| 등분산성 |
신뢰구간 부정확 |
| 정규성 |
검정 통계량 신뢰 ↓ |
| 다중공선성 없음 |
(X^TX)^-1 불안정 |
다중공선성 문제
X^T X가 특이(singular)하거나 조건수(condition number)가 크면:
→ (X^T X)^(-1) 계산 불안정
→ 계수 추정치 분산 폭발
해결: Ridge, Lasso 정규화
면접 포인트
- 공식: β = (X^T X)^(-1) X^T y
- RSS 최소화로 유도
- 다중공선성 → (X^TX)^-1 불안정 → 정규화 필요
Newton's Method와 Gradient Descent 방법에 대해 알고 있나요?
한 줄 정의
GD: 1차 미분(기울기)만 사용 | Newton: 2차 미분(곡률)까지 사용
업데이트 공식
Gradient Descent:
θ_new = θ - α × ∇f(θ)
└─ 학습률 └─ 1차 미분
Newton's Method:
θ_new = θ - H^(-1) × ∇f(θ)
└─ 헤시안 역행렬 (2차 미분)
비교
| 특성 |
Gradient Descent |
Newton's Method |
| 수렴 속도 |
느림 (1차 수렴) |
빠름 (2차 수렴) |
| 계산 비용 |
O(n) |
O(n³) 헤시안 계산 |
| 메모리 |
O(n) |
O(n²) 헤시안 저장 |
| 스케일링 |
대규모 OK |
소규모만 가능 |
| 학습률 |
필요 |
불필요 (자동 조절) |
직관적 이해
GD: 기울기 방향으로 내려감
"눈 감고 경사를 느끼며 걷기"
- 경사만 알고, 얼마나 걸을지는 학습률로 결정
Newton: 곡률까지 고려
"지형 곡률을 보고 최적 스텝 계산"
- 볼록하면 크게, 가파르면 작게 자동 조절
GD Newton
↘ ↘
↘ ↘
↘ ●
↘ (많은 스텝) (적은 스텝)
코드 비교
# Gradient Descent
def gradient_descent(f, grad_f, x0, lr=0.01, n_iter=100):
x = x0
for _ in range(n_iter):
x = x - lr * grad_f(x)
return x
# Newton's Method
def newton_method(f, grad_f, hess_f, x0, n_iter=10):
x = x0
for _ in range(n_iter):
x = x - np.linalg.inv(hess_f(x)) @ grad_f(x)
return x
실무에서의 선택
딥러닝: GD 계열 (SGD, Adam)
→ 수백만 파라미터, 헤시안 불가능
소규모 최적화: Newton 또는 Quasi-Newton (BFGS)
→ scikit-learn의 solver='lbfgs'
Newton의 근사: L-BFGS
→ 헤시안 근사로 메모리 절약
면접 포인트
- GD: 1차 미분, 느리지만 스케일 가능
- Newton: 2차 미분, 빠르지만 계산 비용 큼
- 딥러닝 = GD / 소규모 = Newton (또는 L-BFGS)
XGBoost을 아시나요?
한 줄 정의
Gradient Boosting의 최적화된 구현으로, 정규화와 병렬처리를 추가한 앙상블 기법
XGBoost의 특징
| 특징 |
설명 |
| 정규화 |
L1, L2 정규화로 과적합 방지 |
| 병렬처리 |
피처 단위 병렬 → 빠른 학습 |
| 결측치 처리 |
자동 결측치 처리 |
| 가지치기 |
max_depth로 트리 크기 제한 |
| Early Stopping |
검증 성능 기반 조기 종료 |
Gradient Boosting 원리
1. 초기 모델 f₀(x) = 평균값
2. 잔차(residual) 계산: r₁ = y - f₀(x)
3. 잔차를 예측하는 트리 h₁(x) 학습
4. 모델 업데이트: f₁(x) = f₀(x) + η·h₁(x)
5. 반복
최종: F(x) = f₀ + η·h₁ + η·h₂ + ... + η·hₘ
XGBoost 목적 함수
Obj = Σ L(yᵢ, ŷᵢ) + Σ Ω(fₖ)
└─ 손실 └─ 정규화
Ω(f) = γT + ½λΣw²
└─ 리프 수 └─ 리프 가중치 L2
코드 예시
import xgboost as xgb
from sklearn.model_selection import train_test_split
# 데이터 준비
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2)
dtrain = xgb.DMatrix(X_train, label=y_train)
dval = xgb.DMatrix(X_val, label=y_val)
# 파라미터
params = {
'objective': 'binary:logistic',
'max_depth': 6,
'learning_rate': 0.1,
'subsample': 0.8,
'colsample_bytree': 0.8,
'reg_lambda': 1.0, # L2
'reg_alpha': 0.0, # L1
}
# 학습 (Early Stopping)
model = xgb.train(
params, dtrain,
num_boost_round=1000,
evals=[(dval, 'val')],
early_stopping_rounds=50
)
XGBoost vs LightGBM vs CatBoost
|
XGBoost |
LightGBM |
CatBoost |
| 속도 |
빠름 |
더 빠름 |
중간 |
| 결측치 |
자동 |
자동 |
자동 |
| 범주형 |
수동 인코딩 |
지원 |
네이티브 지원 |
| 성장 방식 |
level-wise |
leaf-wise |
level-wise |
면접 포인트
- Gradient Boosting + 정규화 + 병렬처리
- 목적함수: 손실 + 정규화 (γT + λw²)
- 테이블 데이터 경진대회의 표준 모델
앙상블 방법엔 어떤 것들이 있나요?
한 줄 정의
여러 모델의 예측을 결합하여 단일 모델보다 좋은 성능을 얻는 기법
앙상블 유형
앙상블
├── Bagging (Bootstrap Aggregating)
│ └── Random Forest
│
├── Boosting
│ ├── AdaBoost
│ ├── Gradient Boosting
│ ├── XGBoost
│ └── LightGBM
│
├── Stacking
│ └── 메타 모델로 결합
│
└── Voting
├── Hard Voting (다수결)
└── Soft Voting (확률 평균)
Bagging vs Boosting
|
Bagging |
Boosting |
| 학습 방식 |
병렬 (독립) |
순차 (의존) |
| 샘플링 |
Bootstrap (복원추출) |
가중치 조절 |
| 목표 |
분산(Variance) 감소 |
편향(Bias) 감소 |
| 과적합 |
강건함 |
주의 필요 |
| 대표 |
Random Forest |
XGBoost, LightGBM |
Bagging:
데이터 → [샘플1] → 모델1 ↘
→ [샘플2] → 모델2 → 평균/투표 → 결과
→ [샘플3] → 모델3 ↗
Boosting:
데이터 → 모델1 → 오차 → 모델2 → 오차 → 모델3 → 합산
↑ 틀린 것에 집중
Stacking
Level 0 (Base Models):
데이터 → [RF, XGB, SVM, NN] → 예측들
Level 1 (Meta Model):
예측들 → [Logistic Regression] → 최종 예측
핵심: Base 모델의 예측을 피처로 사용
from sklearn.ensemble import StackingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from xgboost import XGBClassifier
stacking = StackingClassifier(
estimators=[
('rf', RandomForestClassifier()),
('xgb', XGBClassifier())
],
final_estimator=LogisticRegression()
)
Voting
from sklearn.ensemble import VotingClassifier
# Hard Voting: 다수결
hard_vote = VotingClassifier(
estimators=[('rf', rf), ('svm', svm), ('xgb', xgb)],
voting='hard'
)
# Soft Voting: 확률 평균 (보통 더 좋음)
soft_vote = VotingClassifier(
estimators=[('rf', rf), ('svm', svm), ('xgb', xgb)],
voting='soft'
)
면접 포인트
- Bagging: 병렬, 분산↓ (Random Forest)
- Boosting: 순차, 편향↓ (XGBoost)
- Stacking: 메타 모델로 결합
- 다양성(diversity)이 앙상블 성공의 핵심
50개의 작은 의사결정 나무는 큰 의사결정 나무보다 괜찮을까요?
한 줄 답변
대부분의 경우 YES! 작은 트리 앙상블(Random Forest)이 큰 단일 트리보다 일반화 성능이 좋음
왜 작은 트리들이 더 나은가?
큰 단일 트리:
- 높은 Variance (과적합)
- 훈련 데이터에 딱 맞춤
- 새 데이터에 취약
작은 트리 앙상블:
- 개별 트리는 약한 학습기
- 평균/투표로 Variance 감소
- 일반화 성능 ↑
Bias-Variance 관점
|
큰 단일 트리 |
작은 트리 앙상블 |
| Bias |
낮음 |
약간 높음 |
| Variance |
높음 |
낮음 (평균 효과) |
| 과적합 |
심함 |
적음 |
| 일반화 |
나쁨 |
좋음 |
수학적 근거
n개 독립 모델의 평균:
Var(평균) = Var(개별) / n
50개 트리의 분산 = 1개 트리의 분산 / 50
→ 분산이 대폭 감소!
(단, 트리 간 상관관계 있으면 효과 감소)
Random Forest의 추가 트릭
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(
n_estimators=50, # 50개의 작은 트리
max_depth=10, # 깊이 제한 (작은 트리)
max_features='sqrt', # 피처 서브샘플링 → 트리 다양성
bootstrap=True # 데이터 서브샘플링
)
작은 트리 + 피처 서브샘플링
→ 트리 간 상관관계 ↓
→ 앙상블 효과 ↑
예외 상황
작은 트리 앙상블이 안 좋을 때:
1. 해석 가능성이 중요할 때 (단일 트리가 해석 쉬움)
2. 추론 속도가 매우 중요할 때 (50배 느림)
3. 메모리 제약이 심할 때
면접 포인트
- Variance 감소: 평균으로 분산 줄임
- 다양성: 부트스트랩 + 피처 서브샘플링
- 단, 해석 가능성은 단일 트리가 유리
ROC 커브에 대해 설명해주실 수 있으신가요?
한 줄 정의
임계값 변화에 따른 TPR(민감도)와 FPR의 관계를 나타낸 곡선
핵심 개념
ROC: Receiver Operating Characteristic
X축: FPR = FP / (FP + TN) (1 - Specificity)
Y축: TPR = TP / (TP + FN) (Recall, Sensitivity)
각 점 = 특정 임계값(threshold)에서의 (FPR, TPR)
ROC 커브 해석
TPR
↑
1 │ ●───────● 완벽한 모델 (AUC=1)
│ ╱
│ ╱ 좋은 모델
│ ╱
│╱ ╱
●────● 랜덤 (AUC=0.5)
└──────────→ FPR
0 1
왼쪽 위로 볼록할수록 좋은 모델
AUC (Area Under Curve)
AUC = ROC 곡선 아래 면적
AUC = 1.0: 완벽한 분류
AUC = 0.9: 매우 좋음
AUC = 0.8: 좋음
AUC = 0.7: 보통
AUC = 0.5: 랜덤 (의미 없음)
AUC < 0.5: 예측 뒤집으면 나음
코드 예시
from sklearn.metrics import roc_curve, roc_auc_score
import matplotlib.pyplot as plt
# ROC 커브 데이터
fpr, tpr, thresholds = roc_curve(y_true, y_prob)
# AUC 계산
auc = roc_auc_score(y_true, y_prob)
# 시각화
plt.plot(fpr, tpr, label=f'ROC (AUC={auc:.3f})')
plt.plot([0, 1], [0, 1], 'k--', label='Random')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.legend()
plt.show()
ROC vs PR Curve
|
ROC Curve |
PR Curve |
| 축 |
FPR vs TPR |
Recall vs Precision |
| 불균형 데이터 |
낙관적 (TN 많으면 FPR↓) |
민감하게 반영 |
| 추천 상황 |
균형 데이터 |
불균형 데이터 |
불균형 데이터에서:
- ROC AUC가 높아도 PR AUC가 낮을 수 있음
- 양성 클래스가 중요하면 PR Curve 사용
최적 임계값 찾기
# Youden's J statistic
optimal_idx = np.argmax(tpr - fpr)
optimal_threshold = thresholds[optimal_idx]
# 또는 비용 기반으로 선택
# FP 비용과 FN 비용에 따라 다르게
면접 포인트
- 임계값 무관 모델 비교 가능
- AUC: 0.5 = 랜덤, 1.0 = 완벽
- 불균형 데이터에서는 PR Curve가 더 적합
서버 100대에서 인공신경망보다 Random Forest를 써야하는 이유는?
한 줄 답변
병렬화 용이성과 통신 오버헤드 최소화 때문
Random Forest의 분산 처리 장점
Random Forest 분산 학습:
서버1: 트리 1~10 학습 (독립)
서버2: 트리 11~20 학습 (독립)
...
서버100: 트리 991~1000 학습 (독립)
→ 각 서버가 독립적으로 학습
→ 서버 간 통신 불필요!
→ 마지막에 모델만 모아서 앙상블
Neural Network의 분산 처리 어려움
신경망 분산 학습 (Data Parallel):
서버1: 배치1 → gradient1 ↘
서버2: 배치2 → gradient2 → 평균 → 파라미터 업데이트
... ↗ (모든 서버 동기화)
서버100: gradient100
문제:
- 매 스텝마다 gradient 동기화 필요
- 통신 병목 (수백MB~GB 전송)
- 하나 느리면 전체가 기다림
비교
|
Random Forest |
Neural Network |
| 병렬화 |
Embarrassingly Parallel |
동기화 필요 |
| 통신 |
거의 없음 |
매우 많음 |
| 확장성 |
선형 확장 |
통신 병목 |
| 장애 허용 |
일부 실패해도 OK |
동기화 깨짐 |
| 구현 난이도 |
쉬움 |
복잡함 |
실무 상황
서버 100대 상황:
- 네트워크 지연, 불안정성 존재
- 일부 서버 장애 가능
- 단순한 아키텍처 선호
Random Forest가 적합:
✅ 각 서버 독립 작업
✅ 장애 허용
✅ 통신 최소
✅ 쉬운 구현
Neural Network 문제:
❌ 동기화 필요
❌ 통신 병목
❌ All-reduce 구현 복잡
❌ 장애 시 전체 영향
분산 NN이 필요하면?
# Horovod, PyTorch DDP 등 전문 프레임워크 필요
import horovod.torch as hvd
hvd.init()
# 또는 Parameter Server 아키텍처
# 또는 Ray, Spark ML 파이프라인
면접 포인트
- Embarrassingly Parallel: RF 트리는 완전 독립
- 통신 오버헤드: NN은 gradient 동기화 필요
- 단순 분산 환경에서는 RF가 훨씬 효율적
머신러닝적 접근방법과 통계적 접근방법의 차이는?
한 줄 정의
통계: 데이터 이해와 추론 | ML: 예측 성능 최적화
핵심 차이
| 관점 |
통계적 접근 |
머신러닝 접근 |
| 목표 |
이해, 추론, 인과관계 |
예측 성능 |
| 모델 |
가정 기반 (정규성 등) |
데이터 기반 |
| 해석 |
계수 의미 중요 |
블랙박스 허용 |
| 평가 |
p-value, 신뢰구간 |
정확도, AUC |
| 데이터 |
적은 데이터도 가능 |
많은 데이터 필요 |
예시: 집값 예측
통계적 접근:
- "방 개수가 집값에 미치는 영향은?"
- 선형회귀, 계수 해석, p-value 확인
- "방이 1개 늘면 집값 $10,000 증가 (p<0.05)"
머신러닝 접근:
- "집값을 가장 정확히 예측하는 모델은?"
- XGBoost, 신경망 등 시도
- "RMSE가 가장 낮은 모델 선택"
- 왜 그 예측인지는 덜 중요
철학적 차이
통계:
"데이터가 어떤 확률 분포에서 생성되었는가?"
→ 모집단 추정, 가설 검정
머신러닝:
"어떤 함수가 입력을 출력으로 가장 잘 매핑하는가?"
→ 예측 오차 최소화, 일반화
현실에서는 융합
실무에서:
1. 탐색적 분석 (통계) → 데이터 이해
2. 피처 엔지니어링 (통계 + ML)
3. 모델링 (ML) → 예측
4. 해석 (통계 + XAI) → 설명
예: 금융 대출 모델
- ML로 신용 예측
- 통계적 해석으로 규제 준수 (왜 거절했는지 설명)
언제 무엇을?
| 상황 |
적합한 접근 |
| 인과관계 규명 |
통계 |
| 가설 검정 |
통계 |
| 예측 성능 중요 |
ML |
| 데이터 적음 |
통계 |
| 해석 불필요 |
ML |
| 규제 환경 |
통계 + 해석 가능 ML |
면접 포인트
- 통계: 이해, 추론, 인과관계 (p-value)
- ML: 예측 성능 (RMSE, AUC)
- 실무는 둘의 융합이 필요
feature vector란 무엇일까요?
한 줄 정의
샘플의 특성(feature)들을 숫자 벡터로 표현한 것
직관적 이해
사람 데이터:
- 이름: "철수" (문자열 - 모델이 못 읽음)
- 키: 175 (숫자)
- 몸무게: 70 (숫자)
- 성별: "남" (범주형)
Feature Vector로 변환:
[175, 70, 1] ← 모델이 입력으로 받을 수 있는 형태
키 몸무게 성별(남=1)
왜 필요한가?
ML 모델 = 수학 함수
→ 숫자만 처리 가능!
모든 데이터를 숫자 벡터(feature vector)로 변환해야 함
이미지: 픽셀값 → [0.2, 0.5, 0.1, ...]
텍스트: 단어 → [TF-IDF 벡터] 또는 [임베딩]
범주형: One-hot → [0, 1, 0, 0]
Feature Vector 생성 예시
import numpy as np
from sklearn.preprocessing import StandardScaler, OneHotEncoder
# 숫자형 특성
numerical = np.array([[175, 70], [160, 55]])
# 범주형 특성
categorical = np.array([['남'], ['여']])
encoder = OneHotEncoder(sparse=False)
cat_encoded = encoder.fit_transform(categorical)
# 합쳐서 Feature Vector
feature_vectors = np.hstack([numerical, cat_encoded])
# [[175, 70, 1, 0], ← 철수의 feature vector
# [160, 55, 0, 1]] ← 영희의 feature vector
다양한 데이터 타입
| 데이터 |
Feature Vector 변환 방법 |
| 숫자형 |
그대로 (정규화 권장) |
| 범주형 |
One-hot, Label Encoding |
| 텍스트 |
TF-IDF, Word2Vec, BERT |
| 이미지 |
픽셀값, CNN 특징 |
| 시계열 |
통계량, 시퀀스 인코딩 |
Feature Vector vs Embedding
Feature Vector: 수동 설계된 특성
- 도메인 지식 필요
- 해석 가능
Embedding: 학습된 특성
- Word2Vec, BERT 등
- 자동 학습
- 더 풍부한 의미
둘 다 "숫자 벡터"라는 점은 동일
면접 포인트
- 모든 데이터를 숫자 벡터로 표현
- 각 요소가 하나의 feature
- 피처 엔지니어링 = 좋은 feature vector 만들기
인공신경망의 일반적인 문제점은 무엇일까요?
한 줄 정의
블랙박스, 데이터 요구량, 계산 비용, 과적합 등의 한계
주요 문제점
| 문제 |
설명 |
| 블랙박스 |
왜 그런 예측인지 설명 어려움 |
| 데이터 요구 |
많은 레이블 데이터 필요 |
| 계산 비용 |
GPU 필수, 학습 시간/비용 큼 |
| 하이퍼파라미터 |
튜닝이 많고 어려움 |
| 과적합 |
복잡한 모델, 과적합 쉬움 |
| 불안정성 |
초기화, 순서에 따라 결과 달라짐 |
블랙박스 문제
입력 → [???] → 출력
"왜 이 환자가 고위험인가요?"
→ 설명 못함
규제 환경 (금융, 의료):
- 의사결정 근거 제시 필요
- 블랙박스 모델 사용 제한
해결 시도: XAI (SHAP, LIME, Attention)
데이터 요구량
일반적으로:
- 파라미터 수의 10~100배 데이터 필요
- GPT-3: 1750억 파라미터 → 수천억 토큰 학습
적은 데이터에서:
- 과적합
- 노이즈 학습
해결: Transfer Learning, Few-shot Learning
계산 비용
학습:
- GPT-3: ~$5M 학습 비용
- 일반 모델도 GPU 수일~수주
추론:
- 실시간 서비스 시 지연
- 모바일/엣지 배포 어려움
해결: 양자화, 가지치기, 지식 증류
과적합 대응
# 다양한 정규화 기법 필요
model = Sequential([
Dense(128, activation='relu'),
Dropout(0.5), # Dropout
BatchNormalization(), # Batch Norm
Dense(64, activation='relu',
kernel_regularizer=l2(0.01)), # L2
])
# + Early Stopping, Data Augmentation
전통 ML vs 신경망
| 상황 |
전통 ML |
신경망 |
| 적은 데이터 |
✅ |
❌ |
| 해석 필요 |
✅ |
❌ |
| 빠른 추론 |
✅ |
△ |
| 비정형 데이터 |
❌ |
✅ |
| SOTA 성능 |
△ |
✅ |
면접 포인트
- 블랙박스: 설명 불가 → XAI로 보완
- 데이터/계산 비용: 많은 리소스 필요
- 과적합: Dropout, BN 등 정규화 필수
딥러닝 혁신의 근간은 무엇이라고 생각하시나요?
한 줄 정의
데이터, 컴퓨팅 파워, 알고리즘의 동시 발전
세 가지 근간
딥러닝 혁신 = 데이터 × 컴퓨팅 × 알고리즘
2012년 이전 2012년 이후
데이터 적음 빅데이터, 인터넷
컴퓨팅 CPU GPU, TPU
알고리즘 얕은 네트워크 깊은 네트워크, 새 기법
1. 데이터 폭발
- ImageNet: 1400만 장의 레이블 이미지
- 인터넷: 웹 크롤링으로 대규모 데이터 수집
- SNS/모바일: 사용자 생성 데이터
"딥러닝은 데이터를 먹고 자란다"
2. 컴퓨팅 파워
GPU 병렬 연산:
- CPU: 순차 처리, 4~16 코어
- GPU: 병렬 처리, 수천 코어
행렬 연산에 최적화:
- 딥러닝 = 대규모 행렬 연산
- GPU가 CPU 대비 100배 이상 빠름
클라우드 컴퓨팅:
- AWS, GCP로 누구나 접근 가능
3. 알고리즘 혁신
| 연도 |
혁신 |
영향 |
| 2006 |
DBN 사전학습 |
딥네트워크 학습 가능 |
| 2012 |
AlexNet (ReLU, Dropout) |
CV 혁명 |
| 2014 |
GAN, Adam |
생성모델, 안정적 학습 |
| 2015 |
ResNet (Skip Connection) |
매우 깊은 네트워크 |
| 2017 |
Transformer |
NLP 혁명 → LLM |
| 2020+ |
Scaling Law |
크면 클수록 좋다 |
역사적 관점
1차 AI 겨울 (1970s): 퍼셉트론의 한계
2차 AI 겨울 (1990s): 학습 어려움
돌파구 (2012):
- AlexNet이 ImageNet에서 압도적 성능
- GPU 활용, ReLU, Dropout
이후 폭발적 성장
최근 트렌드: Scaling Law
"모델과 데이터를 키우면 성능이 계속 향상"
GPT-3: 1750억 파라미터
GPT-4: 수조 파라미터 (추정)
→ 컴퓨팅 + 데이터의 중요성 재확인
면접 포인트
- 삼박자: 데이터 + 컴퓨팅(GPU) + 알고리즘
- 2012 AlexNet: 딥러닝 부흥의 시작
- Scaling Law: 크기가 성능을 결정