주식 예측 프로그램/머신러닝

머신러닝 모델 돌릴 때 코드 짜면서 꼭 알아야 할 것들 (feat. 데이터 전처리의 함정들)

Z46 2025. 12. 23. 13:43

AI한테 맡기기 전에 이것부터 알고 시작하자!!

요새 ChatGPT나 Claude한테 "이 데이터 분석 좀 해줘~" 하면 뚝딱뚝딱 코드 짜주잖아요? 근데 진짜 문제는 그 코드를 그냥 돌렸다가는 마음에 안드는 결과가 나온다는 거예요 ㅠㅠ

저도 처음에는 생성형 AI한테 의존하다가 삼일동안 디버깅만 했던 기억이... 결국 깨달은 건 데이터의 특징을 먼저 파악하고 그걸 코드에 반영해야 한다는 거였어요. 알고리즘만 믿다가는 큰코다친다는 얘기죠!

이번 글에서는 머신러닝 모델을 활용해서 데이터 분석할 때 코드 짤 때 주의해야 할 점들을 정리해봤습니다. 특히 실무에서 자주 마주치는 함정들 위주로 다뤄볼게요 ^_^

 

1. 편차가 큰 놈이 더 큰 영향을 준다? - 데이터 스케일링의 비밀

왜 스케일링이 필요한가

데이터를 보면 어떤 피처는 0~1 사이 값인데 어떤 피처는 1000~ 10000 사이 값이잖아요? 이럴 때 스케일이 큰 피처가 모델한테 더 큰 영향을 줄 수 있어요. 예를 들어 집값 예측 모델에서 방 개수(1~5)와 가격(수억 원)을 같이 쓰면, 가격이 압도적으로 큰 영향을 주게 되는 거죠.

그래서 단순히 알고리즘만 의존하면 안 되고, df.describe()를 보고 "아 이게 더 많이 영향 줄 수 있으니 스케일링을 해야겠다"라고 판단할 수 있어야 해요!

언제 스케일링을 해야 하나?

알고리즘 스케일링 필요 여부 이유
SVM, KNN, 선형회귀, 로지스틱회귀 ✅ 필요 거리 기반 또는 경사하강법 사용
딥러닝 모델 ✅ 필요 경사하강법 최적화
트리 기반 모델
(Decision Tree, Random Forest, XGBoost)
❌ 불필요 데이터의 상대적 순서만 중요

주요 스케일링 기법

from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler

# 1. StandardScaler: 평균=0, 분산=1 (정규분포 가정)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X_train)

# 2. MinMaxScaler: 0~1 사이로 변환
scaler = MinMaxScaler()
X_scaled = scaler.fit_transform(X_train)

# 3. RobustScaler: 이상치에 강함 (중앙값 기준)
scaler = RobustScaler()
X_scaled = scaler.fit_transform(X_train)

⚠️ 주의사항:

  • 학습 데이터로 fit()한 스케일러를 테스트 데이터에도 동일하게 적용해야 해요!
  • 테스트 데이터에 다시 fit()하면 데이터 누수(Data Leakage) 발생!
# ❌ 잘못된 예시
scaler.fit(X_train)
X_train_scaled = scaler.transform(X_train)
scaler.fit(X_test)  # 이러면 안됨!
X_test_scaled = scaler.transform(X_test)

# ✅ 올바른 예시
scaler.fit(X_train)
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)  # 학습 데이터 기준으로 변환

2. df.describe() - 데이터의 특징을 한눈에!

AI한테 코드 짜달라고 하기 전에 먼저 데이터 특징부터 파악해야 해요. df.describe()는 그걸 한 번에 보여주는 완전 유용한 함수입니다!

import pandas as pd

# 데이터 기초 통계량 확인
df.describe()

df.describe()가 보여주는 것들:

통계량 의미 왜 중요한가?
count 데이터 개수 결측치 확인
mean 평균 중심 경향 파악
std 표준편차 데이터 분산 정도 (클수록 편차 큼)
min/max 최소/최대값 이상치 존재 여부 판단
25%/50%/75% 사분위수 데이터 분포 확인

예를 들어 표준편차가 엄청 크면 "아 이 피처는 스케일링이 필요하겠구나"라고 판단할 수 있는 거죠! 이런 특성을 생성형 AI한테 같이 넘기면 훨씬 더 정확한 코드를 받을 수 있어요.

# 예시: 데이터 특징 파악
print(df.describe())

# 만약 Age의 std가 15이고, Salary의 std가 50000이면?
# → 스케일 차이가 너무 크니까 스케일링 필요!

3. 데이터 정제 - 여기서 시간 제일 많이 든다노

진짜로 데이터 정제가 머신러닝에서 제일 수고가 많이 드는 부분이에요 ㅠㅠ 데이터 분석의 80%가 전처리라는 말이 괜히 있는 게 아니라는 거...

주요 데이터 정제 작업

작업 설명 코드 예시
결측치 처리 NaN 값 제거 또는 대체 df.fillna(df.mean())
이상치 제거 극단값 처리 df[df['age'] < 100]
중복 제거 중복 데이터 삭제 df.drop_duplicates()
데이터 타입 변환 올바른 타입으로 변환 df['date'] = pd.to_datetime(df['date'])
# 결측치 확인
print(df.isnull().sum())

# 결측치 처리 방법
df.fillna(df.mean(), inplace=True)  # 평균값으로 채우기
df.dropna(inplace=True)  # 결측치 있는 행 삭제

# 이상치 확인 (IQR 방법)
Q1 = df['column'].quantile(0.25)
Q3 = df['column'].quantile(0.75)
IQR = Q3 - Q1
df = df[(df['column'] >= Q1 - 1.5*IQR) & (df['column'] <= Q3 + 1.5*IQR)]

4. RANDOM_STATE - 재현성을 위한 필수 설정

random_state는 완전 중요한데 많이들 간과하는 부분이에요. 이거 설정 안 하면 코드 돌릴 때마다 결과가 달라져요!

RANDOM_STATE가 뭔데?

random_state는 랜덤 시드값을 고정시켜서 같은 코드를 실행하면 항상 같은 결과가 나오게 해줘요. 재현성(Reproducibility)을 위해서는 필수입니다!

from sklearn.model_selection import train_test_split

# random_state 없이 실행하면 매번 다른 train/test 분할
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

# random_state 설정하면 항상 같은 분할
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

왜 42를 많이 쓰나요?

  • 사실 아무 숫자나 써도 돼요! (0, 11, 101 등등)
  • 42는 더글라스 애덤스의 소설 "은하수를 여행하는 히치하이커를 위한 안내서"에서 나온 숫자라 프로그래머들 사이에서 유명해졌어요 ㅋㅋ
  • 중요한 건 같은 숫자를 일관성 있게 사용하는 거예요!

어디에 RANDOM_STATE를 써야 하나?

# 데이터 분할
train_test_split(..., random_state=42)

# 모델 학습
RandomForestClassifier(random_state=42)
XGBClassifier(random_state=42)

# 교차 검증
cross_val_score(..., cv=KFold(n_splits=5, shuffle=True, random_state=42))

5. fit() 함수로 학습시킨다노

fit() 함수는 머신러닝 모델을 학습시키는 핵심 함수예요. 근데 스케일러에서도 쓰고, 모델에서도 쓰니까 헷갈릴 수 있어요!

Scaler의 fit()

# 스케일러를 학습 데이터에 맞춰서 "학습"시킴
scaler = StandardScaler()
scaler.fit(X_train)  # 평균과 표준편차 계산

# 그 다음 변환
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 또는 한 번에
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)  # fit 말고 transform만!

모델의 fit()

from sklearn.ensemble import RandomForestClassifier

# 모델을 학습 데이터로 학습시킴
model = RandomForestClassifier(random_state=42)
model.fit(X_train, y_train)

# 예측
predictions = model.predict(X_test)

⚠️ 핵심:

  • 학습 데이터에만 fit()을 써야 해요!
  • 테스트 데이터에 fit()을 쓰면 데이터 누수 발생!

6. 피처 임포턴스 - 뭐가 중요했는지 뽑아봐라

모델 학습이 끝나면 어떤 피처가 중요한 영향을 줬는지 확인하는 게 중요해요. 이게 바로 피처 임포턴스(Feature Importance)입니다!

피처 임포턴스 확인하기

from sklearn.ensemble import RandomForestClassifier
import pandas as pd

# 모델 학습
model = RandomForestClassifier(random_state=42)
model.fit(X_train, y_train)

# 피처 임포턴스 추출
importances = model.feature_importances_

# DataFrame으로 정리
feature_importance_df = pd.DataFrame({
    'feature': X_train.columns,
    'importance': importances
}).sort_values('importance', ascending=False)

print(feature_importance_df)

피처 임포턴스를 왜 봐야 하나?

이유 설명
모델 해석 어떤 변수가 예측에 중요한지 이해
피처 선택 중요하지 않은 변수 제거로 모델 간소화
도메인 지식 검증 예상과 다른 결과 발견 시 데이터 재검토
비즈니스 인사이트 실무에서 어떤 요인이 중요한지 파악
# 시각화
import matplotlib.pyplot as plt

plt.figure(figsize=(10, 6))
plt.barh(feature_importance_df['feature'], feature_importance_df['importance'])
plt.xlabel('Importance')
plt.title('Feature Importance')
plt.show()

7. 추가로 알면 좋은 팁들

데이터 누수(Data Leakage) 조심!

데이터 누수는 테스트 데이터의 정보가 학습 과정에 새어 들어가는 거예요. 이러면 모델 성능이 비현실적으로 좋게 나와요!

# ❌ 잘못된 예시 - 전체 데이터에 스케일링 후 분할
scaler.fit_transform(X)  # 전체 데이터 사용
X_train, X_test = train_test_split(X, test_size=0.2)

# ✅ 올바른 예시 - 분할 후 스케일링
X_train, X_test = train_test_split(X, test_size=0.2, random_state=42)
scaler.fit(X_train)  # 학습 데이터만 사용
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)

교차 검증(Cross-Validation) 써보자

한 번만 train/test 나누면 운이 좋아서 성능이 좋게 나올 수도 있어요. 교차 검증으로 여러 번 검증하면 더 신뢰할 수 있는 결과가 나와요!

from sklearn.model_selection import cross_val_score, KFold

# 5-Fold 교차 검증
kfold = KFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(model, X, y, cv=kfold, scoring='accuracy')

print(f"평균 정확도: {scores.mean():.3f} (+/- {scores.std():.3f})")

하이퍼파라미터 튜닝

모델 성능을 극대화하려면 하이퍼파라미터를 조정해야 해요!

from sklearn.model_selection import GridSearchCV

# 탐색할 파라미터 설정
param_grid = {
    'n_estimators': [100, 200, 300],
    'max_depth': [10, 20, 30],
    'min_samples_split': [2, 5, 10]
}

# Grid Search
grid_search = GridSearchCV(
    RandomForestClassifier(random_state=42),
    param_grid,
    cv=5,
    scoring='accuracy',
    n_jobs=-1
)

grid_search.fit(X_train, y_train)
print(f"Best params: {grid_search.best_params_}")
print(f"Best score: {grid_search.best_score_:.3f}")

결론: 데이터 이해가 먼저, 코드는 그 다음!

정리하자면 요런 것들이 중요해요:

  1. df.describe()로 데이터 특징 먼저 파악하기 → 스케일링 필요 여부 판단
  2. 데이터 정제에 시간 투자하기 → 쓰레기 데이터는 쓰레기 결과만 나온다
  3. RANDOM_STATE 설정으로 재현성 확보 → 같은 결과를 계속 얻을 수 있음
  4. fit()은 학습 데이터에만 → 테스트 데이터 누수 방지
  5. 피처 임포턴스로 모델 해석 → 어떤 변수가 중요한지 파악
  6. 데이터 누수 조심 → 분할 후 전처리!
  7. 교차 검증으로 신뢰성 확보 → 한 번 평가로는 부족해요

생성형 AI한테 코드 짜달라고 하기 전에 이런 특징들을 먼저 정리해서 같이 넘기면 훨씬 더 좋은 코드를 받을 수 있어요! 데이터의 특징을 모르고 그냥 알고리즘만 돌리는 건 진짜 위험합니다 ^^

끝~ 모두들 행복한 데이터 분석하시길! 🎉


참고 자료


#머신러닝 #데이터분석 #데이터전처리 #피처스케일링 #StandardScaler #MinMaxScaler #파이썬 #sklearn #사이킷런 #데이터과학 #AI #인공지능 #데이터분석팁 #머신러닝입문 #코딩팁 #데이터엔지니어링 #RandomState #피처임포턴스 #교차검증 #데이터누수 #하이퍼파라미터튜닝 #데이터정제 #EDA #탐색적데이터분석 #dfDescribe #판다스 #넘파이 #모델학습 #데이터과학자 #빅데이터 #통계분석