실기 — 전처리부터 평가까지의 흐름
이론이 아니라 순서를 외우는 글이다. 실기 시험장에서는 무엇을 아는지가 아니라 무엇을 손이 기억하는지가 결정한다.
전체 순서
1. 데이터 전처리 sklearn.preprocessing
2. 데이터 분리 sklearn.model_selection.train_test_split
3. 모델 훈련 인스턴스 생성 → .fit(X, y)
4. 모델 검증 KFold(교차검증), GridSearchCV(하이퍼파라미터 탐색)
5. 모델 평가 sklearn.metrics
2번을 1번보다 먼저 하지 않는다는 원칙만 지키면 큰 사고는 안 난다. 스케일러를 전체
데이터에 fit 한 뒤 나누면 테스트 정보가 학습에 새어 든다.
1. 데이터 준비
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
df = pd.read_csv("train.csv")
df = pd.concat([train, test], axis=0)
2. 전처리 (Feature Engineering)
결측 처리
df.isnull().sum() # 어디에 몇 개인지 먼저 본다
df["Age"].fillna(df["Age"].median())
평균이 아니라 중앙값을 기본으로 삼는 편이 낫다. 이상치가 있으면 평균은 끌려간다.
이상치 처리
df.drop(index, axis=0)
df.loc[조건] # 라벨 기준
df.iloc[위치] # 위치 기준
loc 과 iloc 을 헷갈리면 조용히 엉뚱한 행이 지워진다. loc 은 라벨, iloc 은 정수 위치다.
탐색과 파생변수
import matplotlib.pyplot as plt
import seaborn as sns
df.info()
df.describe()
df["Cabin"].unique()
pd.get_dummies(df) # 원-핫 인코딩
df["Title"] = df["Name"].str.extract(r"([A-Za-z]+)\.", expand=False)
df["Sex"] = df["Sex"].map({"male": 0, "female": 1})
df["Age"] = df["Age"].astype("int")
df["Embarked"] = df["Embarked"].replace("S", 0)
스케일링
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler
scaler = StandardScaler() # 인스턴스 생성
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test) # test 는 transform 만
| 스케일러 | 언제 |
|---|---|
| StandardScaler | 평균 0, 분산 1. 기본값 |
| MinMaxScaler | 0~1 로. 범위가 정해진 값일 때 |
| RobustScaler | 중앙값과 IQR. 이상치가 있을 때 |
테스트 세트에는 fit_transform 이 아니라 transform 을 쓴다. 학습 세트의 기준으로
변환해야 같은 자로 잰 것이 된다. 여기서 실수하면 점수가 이상하게 좋아지고, 그게 더 나쁘다.
3~4. 훈련과 검증
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import KFold, cross_val_score, GridSearchCV
kfold = KFold(n_splits=3, shuffle=True, random_state=1)
grid_model = GridSearchCV(
estimator=pipe,
param_grid=param_grid,
cv=kfold,
n_jobs=-1,
).fit(X_train, y_train)
cross_val_score 의 scoring 에 넣을 수 있는 값들:
accuracy · average_precision · f1 · log_loss · mean_squared_error
precision · r2 · recall · roc_auc
5. 평가
from sklearn.metrics import (
confusion_matrix, accuracy_score,
precision_score, recall_score, f1_score,
)
f1_score(y_true, y_pred)
지표를 무엇으로 볼지는 평가 지표 글에 정리해 두었다.
분석 종류에 따른 선택
( ) 안의 것은 제목만 언급하고 지나간 분석이다.
| 종류 | 독립변수 X | 종속변수 Y | 알고리즘 | |
|---|---|---|---|---|
| 지도 | 분류 | 연속 | 이산 | KNN, SVC, NaiveBayes, XGBoost, (Decision Tree, Random Forest) |
| 회귀 | 연속 | 연속 | (Linear Regression, Ridge, Lasso) | |
| 비지도 | 군집 | 연속 | 잠재 이산 | 계층적: AgglomerativeClustering / 비계층적: KMeans, DBSCAN |
| 차원 축소 | 연속 | 잠재 연속 | PCA |
종속변수 Y 가 이산이면 분류, 연속이면 회귀다. 비지도는 Y 가 “잠재적으로” 존재한다고 보는 것이고, 그래서 군집을 이산, 차원 축소를 연속에 놓았다.
AutoML 로 한 번에
시간이 없을 때 쓰려고 적어 둔 것이다.
from lightautoml.tasks import Task
from lightautoml.automl.presets.tabular_presets import TabularAutoML
from sklearn.metrics import f1_score
automl = TabularAutoML(
task=Task("binary", metric=lambda y_true, y_pred: f1_score(y_true, (y_pred > 0.5) * 1))
)
oof_pred = automl.fit_predict(train, roles={"target": "Survived", "drop": ["PassengerId"]})
test_pred = automl.predict(test)
pd.DataFrame({
"PassengerId": test.PassengerId,
"Survived": (test_pred.data[:, 0] > 0.5) * 1,
}).to_csv("submit.csv", index=False)
분위수로 구간을 잡을 때:
lower = sep.groupby(["hour", "minute", "x", "y", "direction"]).congestion.quantile(0.15).values
upper = sep.groupby(["hour", "minute", "x", "y", "direction"]).congestion.quantile(0.70).values
오답 노트
시험 준비하며 틀렸던 것들.
- 딥러닝의 한계 — 이론적 근거가 부족하고 해석이 어렵다.
- 탐색적 데이터 분석(EDA) — 분석용 데이터셋의 정합성을 검토하고, 데이터를 요약해 특성을 파악하며, 모델링에 필요한 데이터를 편성한다. 기초 통계량을 산출하고 시각화로 가독성을 높여 특성을 파악하는 분석이다.
- 분석의 네 수준 — 기술(무엇이 일어났나) · 진단(왜 일어났나) · 예측(앞으로 어떻게 될까) · 처방(어떻게 대처할까). 순서대로 어려워지고 가치도 커진다.
- 원천별 수집 방식 — 센서는 센싱, DBMS 는 DB-to-DB 동기화, 동영상은 스트리밍, 웹은 크롤링.
단위 — KB 와 KiB
의외로 자주 나온다.
| 10진 | 2진 | ||
|---|---|---|---|
| KB (킬로바이트) | KiB (키비바이트) | ||
| MB | MiB (메비바이트) | ||
| GB | GiB (기비바이트) | ||
| TB | TiB (테비바이트) | ||
| PB | PiB (페비바이트) | ||
| EB | EiB (엑스비바이트) | ||
| ZB | ZiB (제비바이트) | ||
| YB | YiB (요비바이트) |