🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

Scikit-learn 실전 프로젝트 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 12. 3. · 13 Views

Scikit-learn 실전 프로젝트 완벽 가이드

머신러닝 프로젝트를 처음부터 끝까지 진행하는 방법을 배웁니다. 주제 선정부터 데이터 수집, 전처리, 모델 비교, 튜닝, 그리고 최종 모델 저장까지 실무에서 바로 적용할 수 있는 완전한 워크플로우를 다룹니다.


목차

  1. 프로젝트_주제_선정
  2. 데이터_수집_및_탐색
  3. 전처리_파이프라인_구축
  4. 여러_모델_비교_실험
  5. 하이퍼파라미터_튜닝
  6. 최종_모델_선택_및_저장

1. 프로젝트 주제 선정

김개발 씨는 회사에서 첫 머신러닝 프로젝트를 맡게 되었습니다. 데이터도 있고, 파이썬도 어느 정도 할 줄 아는데, 막상 시작하려니 막막합니다.

"대체 어디서부터 시작해야 하지?"

프로젝트 주제 선정은 머신러닝 프로젝트의 첫 단추입니다. 마치 여행을 떠나기 전에 목적지를 정하는 것과 같습니다.

목적지가 명확해야 어떤 교통수단을 이용할지, 무엇을 준비할지 결정할 수 있듯이, 주제가 명확해야 어떤 데이터가 필요하고 어떤 알고리즘을 사용할지 결정할 수 있습니다.

다음 코드를 살펴봅시다.

# 프로젝트 주제 선정 예시: 고객 이탈 예측
# 비즈니스 문제를 머신러닝 문제로 정의합니다

project_definition = {
    "business_problem": "고객 이탈률 감소",
    "ml_problem_type": "이진 분류(Binary Classification)",
    "target_variable": "churned",  # 이탈 여부 (0 또는 1)
    "success_metric": "F1-Score >= 0.85",
    "available_data": ["고객정보", "거래내역", "서비스이용로그"],
    "timeline": "4주"
}

# 문제 유형에 따른 접근 방식 결정
if project_definition["ml_problem_type"] == "이진 분류(Binary Classification)":
    candidate_models = ["LogisticRegression", "RandomForest", "XGBoost"]
    print(f"후보 모델: {candidate_models}")

김개발 씨는 입사 6개월 차 주니어 데이터 분석가입니다. 어느 날 팀장님이 회의실로 부르더니 이렇게 말했습니다.

"개발 씨, 우리 고객 이탈이 심각해요. 머신러닝으로 뭔가 해볼 수 있을까요?" 김개발 씨는 당황했습니다.

머신러닝 강의는 들었지만, 실제 프로젝트는 처음이었기 때문입니다. 그날 밤, 선배 박시니어 씨에게 조언을 구했습니다.

"주제 선정이 제일 중요해요." 박시니어 씨가 말했습니다. "비즈니스 문제를 머신러닝이 풀 수 있는 형태로 바꿔야 해요." 그렇다면 어떻게 비즈니스 문제를 머신러닝 문제로 바꿀 수 있을까요?

쉽게 비유하자면, 이것은 마치 의사가 환자의 증상을 듣고 검사 항목을 정하는 것과 같습니다. "배가 아파요"라는 말만으로는 치료할 수 없습니다.

어디가, 언제부터, 어떻게 아픈지 구체화해야 합니다. 마찬가지로 "고객 이탈을 줄이고 싶다"는 것도 구체화가 필요합니다.

분류 문제인지 회귀 문제인지 먼저 결정해야 합니다. 고객이 이탈할지 안 할지 예측하는 것은 이진 분류 문제입니다.

반면, 고객이 얼마나 많은 금액을 사용할지 예측하는 것은 회귀 문제입니다. 다음으로 성공 기준을 정해야 합니다.

정확도 90%가 목표인지, F1-Score 0.85가 목표인지 명확히 해야 합니다. 이것이 없으면 프로젝트가 끝났을 때 성공인지 실패인지 알 수 없습니다.

타겟 변수도 중요합니다. 이탈 예측이라면 "이탈 여부"가 타겟 변수가 됩니다.

이 변수가 데이터에 있는지, 어떻게 정의할 것인지 확인해야 합니다. 위 코드를 보면 프로젝트 정의를 딕셔너리로 정리한 것을 볼 수 있습니다.

이렇게 문서화해두면 나중에 방향을 잃지 않습니다. 실제 현업에서는 이 단계에서 이해관계자들과 충분히 논의해야 합니다.

데이터 팀만의 프로젝트가 아니라 비즈니스 팀과 함께하는 프로젝트여야 성공할 수 있습니다. 주의할 점은 너무 거창한 목표를 세우지 않는 것입니다.

처음부터 "AI로 모든 문제를 해결하겠다"는 것은 실패의 지름길입니다. 작고 명확한 문제부터 시작하세요.

김개발 씨는 박시니어 씨의 조언대로 프로젝트 정의서를 작성했습니다. "고객 이탈 여부를 예측하는 이진 분류 모델, 목표 F1-Score 0.85 이상." 이제 방향이 명확해졌습니다.

실전 팁

💡 - 비즈니스 문제를 분류/회귀/군집 중 어떤 유형인지 먼저 파악하세요

  • 성공 기준을 숫자로 명확히 정의하세요 (예: "정확도 85% 이상")
  • 데이터가 실제로 존재하는지, 타겟 변수를 만들 수 있는지 먼저 확인하세요

2. 데이터 수집 및 탐색

프로젝트 주제가 정해진 김개발 씨는 이제 데이터를 모아야 합니다. 그런데 데이터베이스에서 데이터를 가져와 보니 컬럼이 50개가 넘습니다.

"이걸 다 봐야 하나요?" 김개발 씨의 한숨이 깊어집니다.

데이터 수집 및 탐색은 요리 전에 재료를 확인하는 것과 같습니다. 재료의 상태를 확인하지 않고 요리를 시작하면 중간에 낭패를 볼 수 있습니다.

데이터의 크기, 결측치, 분포를 파악해야 다음 단계에서 어떤 전처리가 필요한지 알 수 있습니다.

다음 코드를 살펴봅시다.

import pandas as pd
import numpy as np
from sklearn.datasets import fetch_california_housing

# 데이터 로드 (예시: 캘리포니아 주택 가격 데이터)
data = fetch_california_housing(as_frame=True)
df = data.frame

# 기본 정보 확인
print(f"데이터 크기: {df.shape}")  # (행, 열)
print(f"\n컬럼별 데이터 타입:\n{df.dtypes}")
print(f"\n결측치 개수:\n{df.isnull().sum()}")

# 기술 통계량 확인
print(f"\n기술 통계량:\n{df.describe()}")

# 타겟 변수 분포 확인
print(f"\n타겟 변수 분포:")
print(f"평균: {df['MedHouseVal'].mean():.2f}")
print(f"중앙값: {df['MedHouseVal'].median():.2f}")

김개발 씨가 데이터베이스에서 고객 데이터를 추출했습니다. CSV 파일로 저장하고 주피터 노트북을 열었습니다.

이제 어디서부터 시작해야 할까요? 박시니어 씨가 옆에서 조언합니다.

"데이터를 받으면 항상 같은 순서로 확인해요. 저는 DICE라고 부르는데, Dimension, Info, Count, Explore의 약자예요." Dimension은 데이터의 크기입니다.

df.shape을 실행하면 (행, 열) 형태로 데이터의 차원을 알 수 있습니다. 행이 1000개인지 100만 개인지에 따라 접근 방식이 달라집니다.

Info는 데이터 타입 정보입니다. df.dtypes나 df.info()를 사용합니다.

숫자인 줄 알았는데 문자열로 저장된 컬럼이 있을 수 있습니다. 이런 것을 미리 파악해야 합니다.

Count는 결측치 개수입니다. df.isnull().sum()으로 각 컬럼별 결측치를 확인합니다.

결측치가 80%인 컬럼은 삭제를 고려해야 하고, 10%인 컬럼은 대체를 고려해야 합니다. Explore는 분포 탐색입니다.

df.describe()로 평균, 표준편차, 최솟값, 최댓값을 확인합니다. 이상치가 있는지, 데이터가 한쪽으로 치우쳐 있는지 파악할 수 있습니다.

위 코드에서 사용한 fetch_california_housing은 Scikit-learn에서 제공하는 예제 데이터셋입니다. 실제 프로젝트에서는 pd.read_csv()나 데이터베이스 쿼리로 데이터를 가져옵니다.

데이터 탐색에서 흔히 하는 실수는 시각화 없이 숫자만 보는 것입니다. 히스토그램, 산점도, 상관관계 히트맵을 그려보면 숫자만으로는 보이지 않던 패턴이 보입니다.

또 하나 중요한 것은 타겟 변수의 분포입니다. 이진 분류에서 클래스 비율이 9:1로 불균형하다면 특별한 처리가 필요합니다.

이것을 미리 확인하지 않으면 나중에 모델이 다수 클래스만 예측하는 문제가 생깁니다. 김개발 씨는 데이터를 탐색하다가 놀라운 사실을 발견했습니다.

이탈 고객이 전체의 5%밖에 안 되는 것이었습니다. "이거 불균형 데이터네요." 박시니어 씨가 말했습니다.

"오버샘플링이나 클래스 가중치를 고려해야겠어요."

실전 팁

💡 - 데이터를 받으면 항상 shape, dtypes, isnull, describe 순서로 확인하세요

  • 시각화 도구(matplotlib, seaborn)를 활용해 분포를 눈으로 확인하세요
  • 타겟 변수의 클래스 비율을 반드시 확인하세요

3. 전처리 파이프라인 구축

데이터 탐색을 마친 김개발 씨는 결측치도 있고, 스케일도 제각각인 데이터를 어떻게 처리해야 할지 고민입니다. 하나씩 처리하다 보니 코드가 지저분해지고, 나중에 새 데이터가 들어오면 또 같은 작업을 반복해야 할 것 같습니다.

전처리 파이프라인은 데이터 정제 과정을 자동화하는 것입니다. 마치 공장의 조립 라인처럼, 원재료가 들어가면 완제품이 나오는 시스템을 만드는 것입니다.

Scikit-learn의 Pipeline과 ColumnTransformer를 사용하면 전처리 과정을 깔끔하게 모듈화할 수 있습니다.

다음 코드를 살펴봅시다.

from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.impute import SimpleImputer

# 수치형과 범주형 컬럼 정의
numeric_features = ['age', 'income', 'usage_months']
categorical_features = ['gender', 'plan_type']

# 수치형 전처리: 결측치 중앙값 대체 -> 표준화
numeric_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='median')),
    ('scaler', StandardScaler())
])

# 범주형 전처리: 결측치 최빈값 대체 -> 원핫인코딩
categorical_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='most_frequent')),
    ('onehot', OneHotEncoder(handle_unknown='ignore'))
])

# 컬럼별로 다른 전처리 적용
preprocessor = ColumnTransformer(transformers=[
    ('num', numeric_transformer, numeric_features),
    ('cat', categorical_transformer, categorical_features)
])

김개발 씨가 전처리 코드를 작성하기 시작했습니다. 결측치 처리, 스케일링, 인코딩...

코드가 점점 길어졌습니다. 그런데 문제가 생겼습니다.

"개발 씨, 테스트 데이터에 훈련 데이터의 평균값을 사용하면 안 돼요." 박시니어 씨가 경고했습니다. "그건 **데이터 누수(Data Leakage)**예요." 데이터 누수란 무엇일까요?

쉽게 비유하자면, 시험을 보기 전에 정답지를 슬쩍 본 것과 같습니다. 테스트 데이터의 정보가 훈련 과정에 들어가면 모델 성능이 실제보다 부풀려집니다.

이 문제를 해결하는 것이 바로 Pipeline입니다. Pipeline을 사용하면 전처리 과정이 훈련 데이터에서만 학습되고, 테스트 데이터에는 학습된 파라미터가 적용됩니다.

위 코드를 단계별로 살펴보겠습니다. 먼저 수치형 컬럼과 범주형 컬럼을 분리합니다.

나이, 소득, 이용 개월 수는 숫자이고, 성별과 요금제는 범주입니다. numeric_transformer는 수치형 데이터를 처리합니다.

SimpleImputer로 결측치를 중앙값으로 대체하고, StandardScaler로 평균 0, 표준편차 1로 스케일링합니다. categorical_transformer는 범주형 데이터를 처리합니다.

결측치는 최빈값으로 대체하고, OneHotEncoder로 더미 변수를 만듭니다. handle_unknown='ignore'는 새로운 범주가 나타나도 에러가 나지 않게 합니다.

ColumnTransformer는 이 두 변환기를 합칩니다. 수치형 컬럼에는 numeric_transformer를, 범주형 컬럼에는 categorical_transformer를 적용합니다.

실무에서 이 패턴이 특히 유용한 이유는 재사용성 때문입니다. 한 번 파이프라인을 만들어 두면, 새로운 데이터가 들어와도 preprocessor.transform(new_data) 한 줄로 같은 전처리를 적용할 수 있습니다.

주의할 점은 fit과 transform의 구분입니다. 훈련 데이터에서는 fit_transform을 사용하고, 테스트 데이터에서는 transform만 사용해야 합니다.

이것을 실수하면 데이터 누수가 발생합니다. 김개발 씨는 파이프라인을 완성하고 감탄했습니다.

"이렇게 하면 코드도 깔끔하고, 데이터 누수도 방지되는군요!"

실전 팁

💡 - 반드시 Pipeline을 사용해 전처리와 모델링을 연결하세요

  • 훈련 데이터에서 fit_transform, 테스트 데이터에서 transform만 사용하세요
  • ColumnTransformer의 remainder='passthrough' 옵션으로 나머지 컬럼도 포함시킬 수 있습니다

4. 여러 모델 비교 실험

전처리 파이프라인을 완성한 김개발 씨 앞에 새로운 고민이 생겼습니다. "로지스틱 회귀를 쓸까, 랜덤 포레스트를 쓸까, 아니면 XGBoost가 좋을까?" 어떤 모델이 최선인지 어떻게 알 수 있을까요?

모델 비교 실험은 여러 후보 모델을 동일한 조건에서 평가하는 것입니다. 마치 오디션에서 여러 지원자를 같은 기준으로 평가하는 것과 같습니다.

교차 검증을 통해 각 모델의 성능을 객관적으로 비교하고, 가장 적합한 모델을 선별합니다.

다음 코드를 살펴봅시다.

from sklearn.model_selection import cross_val_score, train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.svm import SVC

# 전처리기와 모델을 결합한 파이프라인 생성
def create_pipeline(model):
    return Pipeline(steps=[
        ('preprocessor', preprocessor),
        ('classifier', model)
    ])

# 비교할 모델 목록
models = {
    'LogisticRegression': LogisticRegression(max_iter=1000),
    'RandomForest': RandomForestClassifier(n_estimators=100, random_state=42),
    'GradientBoosting': GradientBoostingClassifier(random_state=42),
    'SVM': SVC(random_state=42)
}

# 각 모델의 교차 검증 점수 비교
results = {}
for name, model in models.items():
    pipeline = create_pipeline(model)
    scores = cross_val_score(pipeline, X_train, y_train, cv=5, scoring='f1')
    results[name] = {'mean': scores.mean(), 'std': scores.std()}
    print(f"{name}: F1 = {scores.mean():.4f} (+/- {scores.std():.4f})")

김개발 씨는 온라인 강의에서 "XGBoost가 최고"라는 말을 들었습니다. 그래서 바로 XGBoost를 적용하려고 했습니다.

그런데 박시니어 씨가 제동을 걸었습니다. "항상 XGBoost가 최고인 건 아니에요.

데이터에 따라 다릅니다. 실험해봐야 알 수 있어요." 모델 비교 실험은 왜 필요할까요?

쉽게 비유하자면, 운동화를 살 때 여러 브랜드를 신어보는 것과 같습니다. 아무리 좋은 브랜드라도 내 발에 맞지 않으면 소용없습니다.

마찬가지로 아무리 유명한 알고리즘이라도 내 데이터에 맞지 않으면 성능이 좋지 않습니다. 비교할 때 가장 중요한 것은 동일한 조건입니다.

모든 모델이 같은 데이터, 같은 전처리, 같은 평가 방식을 거쳐야 공정한 비교가 가능합니다. 위 코드에서 create_pipeline 함수는 전처리기와 모델을 결합합니다.

이렇게 하면 모든 모델이 동일한 전처리 과정을 거칩니다. cross_val_score는 교차 검증을 수행합니다.

cv=5는 데이터를 5등분하여 5번 훈련과 검증을 반복한다는 의미입니다. 한 번의 검증보다 신뢰도가 높은 결과를 얻을 수 있습니다.

scoring='f1'은 평가 지표를 F1-Score로 설정한 것입니다. 불균형 데이터에서는 정확도보다 F1-Score가 더 적합한 평가 지표입니다.

결과를 보면 평균과 표준편차가 함께 출력됩니다. 평균이 높으면서 표준편차가 낮은 모델이 안정적으로 좋은 모델입니다.

평균이 높아도 표준편차가 크면 데이터에 따라 성능이 들쭉날쭉하다는 의미입니다. 실무에서 주의할 점은 과적합입니다.

훈련 데이터에서만 성능이 좋고 테스트 데이터에서 성능이 떨어지면 과적합입니다. 교차 검증 점수와 테스트 점수의 차이가 크다면 과적합을 의심해야 합니다.

김개발 씨는 실험 결과를 보고 놀랐습니다. 예상과 달리 로지스틱 회귀가 가장 좋은 성능을 보였습니다.

"단순한 모델이 꼭 나쁜 건 아니네요." 박시니어 씨가 웃으며 말했습니다. "오컴의 면도날이라고 하죠.

같은 성능이라면 단순한 모델이 낫습니다."

실전 팁

💡 - 최소 3-4개의 서로 다른 계열의 모델을 비교하세요

  • 교차 검증으로 신뢰도 높은 결과를 얻으세요
  • 평균 성능뿐 아니라 표준편차도 확인하세요

5. 하이퍼파라미터 튜닝

모델 비교에서 랜덤 포레스트가 가장 좋은 결과를 보였습니다. 김개발 씨는 이제 이 모델을 더 좋게 만들고 싶습니다.

"트리 개수를 100개에서 200개로 늘리면 좋아질까요?" 하지만 어떤 조합이 최선인지 일일이 시도해보기엔 경우의 수가 너무 많습니다.

하이퍼파라미터 튜닝은 모델의 설정값을 최적화하는 과정입니다. 마치 라디오 주파수를 맞추는 것과 같습니다.

조금씩 돌려가며 가장 깨끗한 소리가 나는 지점을 찾습니다. GridSearchCV와 RandomizedSearchCV를 사용하면 이 과정을 자동화할 수 있습니다.

다음 코드를 살펴봅시다.

from sklearn.model_selection import GridSearchCV, RandomizedSearchCV
from sklearn.ensemble import RandomForestClassifier
import numpy as np

# 탐색할 하이퍼파라미터 그리드 정의
param_grid = {
    'classifier__n_estimators': [100, 200, 300],
    'classifier__max_depth': [10, 20, 30, None],
    'classifier__min_samples_split': [2, 5, 10],
    'classifier__min_samples_leaf': [1, 2, 4]
}

# 파이프라인 생성
pipeline = Pipeline(steps=[
    ('preprocessor', preprocessor),
    ('classifier', RandomForestClassifier(random_state=42))
])

# 그리드 서치 실행
grid_search = GridSearchCV(
    pipeline, param_grid, cv=5, scoring='f1', n_jobs=-1, verbose=1
)
grid_search.fit(X_train, y_train)

# 최적 하이퍼파라미터와 점수 출력
print(f"최적 파라미터: {grid_search.best_params_}")
print(f"최적 F1 점수: {grid_search.best_score_:.4f}")

김개발 씨는 랜덤 포레스트의 여러 파라미터를 보며 막막해졌습니다. n_estimators, max_depth, min_samples_split, min_samples_leaf...

이것들을 어떻게 조합해야 할까요? 박시니어 씨가 설명했습니다.

"일일이 해볼 필요 없어요. GridSearchCV가 자동으로 모든 조합을 시도해줍니다." 하이퍼파라미터란 무엇일까요?

모델이 학습하는 파라미터와는 다릅니다. 모델이 학습하기 전에 우리가 미리 정해주는 값입니다.

마치 요리 레시피에서 "중불에서 5분"이라고 할 때, 불의 세기와 시간은 요리사가 정하는 것처럼요. GridSearchCV는 격자 탐색이라고도 합니다.

지정한 모든 파라미터 조합을 시도합니다. 위 코드에서는 3 x 4 x 3 x 3 = 108개의 조합을 시도합니다.

여기에 5-fold 교차 검증을 곱하면 총 540번의 훈련이 이루어집니다. 코드에서 주목할 부분은 파라미터 이름입니다.

'classifier__n_estimators'처럼 더블 언더스코어를 사용합니다. 이것은 파이프라인에서 'classifier'라는 이름의 단계에 있는 n_estimators를 의미합니다.

n_jobs=-1은 컴퓨터의 모든 CPU 코어를 사용하라는 의미입니다. 탐색 시간을 크게 줄일 수 있습니다.

그리드 서치의 단점은 시간이 오래 걸린다는 것입니다. 파라미터 조합이 많아지면 기하급수적으로 시간이 늘어납니다.

이럴 때는 RandomizedSearchCV를 사용합니다. 모든 조합 대신 지정한 횟수만큼만 무작위로 탐색합니다.

실무에서는 두 가지를 조합해 사용합니다. 먼저 RandomizedSearchCV로 대략적인 범위를 찾고, 그 주변에서 GridSearchCV로 세밀하게 탐색합니다.

주의할 점은 과적합의 위험입니다. 하이퍼파라미터를 너무 세밀하게 튜닝하면 검증 데이터에 과적합될 수 있습니다.

이것을 방지하기 위해 최종 평가는 반드시 별도의 테스트 데이터로 해야 합니다. 김개발 씨는 그리드 서치를 돌려놓고 커피를 마시며 기다렸습니다.

30분 후, 최적의 조합이 찾아졌습니다. F1-Score가 0.87에서 0.91로 올랐습니다!

실전 팁

💡 - 먼저 넓은 범위로 RandomizedSearchCV를 실행하고, 좁은 범위로 GridSearchCV를 실행하세요

  • n_jobs=-1로 병렬 처리를 활성화하세요
  • 최적 파라미터를 찾은 후에도 반드시 별도 테스트 셋으로 최종 검증하세요

6. 최종 모델 선택 및 저장

하이퍼파라미터 튜닝까지 완료한 김개발 씨는 이제 프로젝트의 마지막 단계에 왔습니다. 최적화된 모델을 저장하고, 나중에 실제 서비스에서 사용할 수 있게 만들어야 합니다.

"모델을 어떻게 저장하고 불러올 수 있나요?"

모델 저장은 훈련된 모델을 파일로 보관하는 것입니다. 마치 완성된 요리를 냉동 보관하는 것과 같습니다.

나중에 필요할 때 해동해서 바로 사용할 수 있습니다. joblib을 사용하면 Scikit-learn 모델과 파이프라인을 효율적으로 저장하고 불러올 수 있습니다.

다음 코드를 살펴봅시다.

import joblib
from sklearn.metrics import classification_report, confusion_matrix

# 최적 모델로 최종 훈련 (전체 훈련 데이터 사용)
best_model = grid_search.best_estimator_
best_model.fit(X_train, y_train)

# 테스트 데이터로 최종 평가
y_pred = best_model.predict(X_test)
print("=== 최종 모델 성능 ===")
print(classification_report(y_test, y_pred))
print(f"\n혼동 행렬:\n{confusion_matrix(y_test, y_pred)}")

# 모델 저장
model_path = 'customer_churn_model.joblib'
joblib.dump(best_model, model_path)
print(f"\n모델이 '{model_path}'에 저장되었습니다.")

# 나중에 모델 불러오기
loaded_model = joblib.load(model_path)
new_prediction = loaded_model.predict(new_customer_data)

프로젝트의 대단원이 다가왔습니다. 김개발 씨는 몇 주간의 노력 끝에 F1-Score 0.91을 달성한 모델을 완성했습니다.

이제 이 모델을 실제 서비스에 적용해야 합니다. 박시니어 씨가 마지막 조언을 건넵니다.

"모델만 저장하면 안 돼요. 파이프라인 전체를 저장해야 합니다." 왜 파이프라인 전체를 저장해야 할까요?

쉽게 비유하자면, 케이크를 배달할 때 케이크만 보내는 게 아니라 상자와 함께 보내는 것과 같습니다. 모델은 전처리된 데이터를 기대합니다.

전처리기 없이 모델만 저장하면, 나중에 새 데이터를 받았을 때 같은 전처리를 다시 구현해야 합니다. 위 코드에서 best_model은 GridSearchCV가 찾은 최적 파이프라인입니다.

전처리기와 모델이 함께 포함되어 있습니다. 이것을 통째로 저장하면 나중에 불러올 때도 전처리가 자동으로 적용됩니다.

classification_report는 정밀도(Precision), 재현율(Recall), F1-Score를 한눈에 보여줍니다. 클래스별 성능을 파악할 수 있어서 유용합니다.

confusion_matrix는 혼동 행렬입니다. 실제 값과 예측 값을 교차표로 보여줍니다.

모델이 어떤 유형의 실수를 많이 하는지 파악할 수 있습니다. joblib은 Scikit-learn 모델을 저장하는 데 최적화된 라이브러리입니다.

pickle보다 대용량 numpy 배열을 효율적으로 처리합니다. 대부분의 Scikit-learn 모델에는 joblib을 사용하는 것이 좋습니다.

모델을 배포할 때 주의할 점이 있습니다. 훈련할 때 사용한 라이브러리 버전을 기록해두어야 합니다.

Scikit-learn 버전이 다르면 저장된 모델을 불러올 수 없는 경우가 있습니다. 또한 모델의 성능은 시간이 지나면 저하될 수 있습니다.

이것을 모델 드리프트라고 합니다. 정기적으로 모델 성능을 모니터링하고 필요하면 재훈련해야 합니다.

김개발 씨는 모델을 저장하고 테스트를 완료했습니다. 팀장님에게 보고서를 제출하며 말했습니다.

"고객 이탈 예측 모델이 완성되었습니다. F1-Score 0.91입니다!" 팀장님이 미소를 지었습니다.

"잘했어요, 김개발 씨. 이제 마케팅팀과 협업해서 실제 캠페인에 적용해봅시다." 이렇게 김개발 씨의 첫 머신러닝 프로젝트가 성공적으로 마무리되었습니다.

주제 선정부터 데이터 탐색, 전처리, 모델 비교, 튜닝, 저장까지. 이 과정을 반복하다 보면 여러분도 어느새 머신러닝 전문가가 되어 있을 것입니다.

실전 팁

💡 - 모델만 저장하지 말고 전처리 파이프라인 전체를 저장하세요

  • 라이브러리 버전을 requirements.txt에 기록해두세요
  • 배포 후에도 모델 성능을 주기적으로 모니터링하세요

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Python#Scikit-learn#MachineLearning#DataScience#ModelTraining#Pipeline#Machine Learning,Python

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.