본문 바로가기
AI/AI 부트캠프

[AI 부트캠프] DAY 58 - 머신러닝 프로젝트 2

by HOHHOH 2023. 10. 13.

[오늘의 일지]

머신러닝 프로젝트 - EDA, LGBM

[상세 내용]

머신러닝 프로젝트

EDA

- 어제 일지에서 소개했던 베이스라인 코드에 의하면 사실 간단하지만 전처리가 다 되어 있어서 머신러닝 대회를 처음 진행하는 입장에서 뭔가 할 게 없다고 느껴졌습니다. 다만 풍향과 관련된 데이터들이 결측치를 많이 가지고 있었는데 그냥 평균값으로 대체하는 것에 대해서 뭔가 찜찜함이 있었지만 일단은 넘어가고 LGBM을 돌렸는데 평가지표가 생각보다 잘 안 나오는 느낌이 들어서 결측치를 다른 방법으로 대체해 보기로 했습니다. 저희는 수업시간에 배운 대로 처음에는 KNN(K Neighbor Nearest)을 사용해 보았습니다. 근데 생각보다 결측치의 양이 많아서 그런가 시간은 시간대로 다 잡아먹고 결과는 실패로 나왔습니다.

# knn 예시 코드입니다.
import numpy as np
from sklearn.impute import KNNImputer

# 예제 데이터셋 생성 (NaN은 결측치를 나타냅니다)
X = np.array([[1, 2, np.nan],
              [4, 5, 6],
              [7, 8, 9],
              [10, 11, 12]])

# KNNImputer 객체 생성
imputer = KNNImputer(n_neighbors=2)  # n_neighbors는 주변 이웃의 수를 나타냅니다

# 결측치 대체
X_imputed = imputer.fit_transform(X)

print("원본 데이터:\n", X)
print("결측치 대체된 데이터:\n", X_imputed)

어쩔 수 없이 강사님께 조언을 구해보았는데 두 가지를 추천해 주셨습니다. 첫 번째는 비교적 간단한 선형 interpolation이었고 두 번째는 Gaussian Process였습니다. Gaussian Process가 더 결측치를 잘 대체할 것으로 느껴서 시도해 보았지만 ram을 너무 많이 사용하는 관계로 구글 colab에서 거부하였습니다. 그렇게 저희는 선형 interpolation으로 결측치를 대체하였습니다.

# 선형 interpolation 예시 코드

import pandas as pd

# 예제 데이터 생성 (NaN은 결측치를 나타냅니다)
data = pd.DataFrame({'A': [1, 4, 7, 10],
                     'B': [2, np.nan, 8, 11],
                     'C': [np.nan, 6, 9, 12]})

# 선형 interpolate() 사용
interpolated_data = data.interpolate(method='linear', axis=0)

print("원본 데이터:\n", data)
print("결측치 대체된 데이터:\n", interpolated_data)

# Gaussian Process 예시 코드

import numpy as np
from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import RBF, ConstantKernel as C

# 가상 데이터 생성
np.random.seed(0)
X = np.sort(5 * np.random.rand(80, 1), axis=0)
y = np.sin(X).ravel()
y[::5] += 3 * (0.5 - np.random.rand(16))

# 가우시안 프로세스 모델 정의
kernel = C(1.0, (1e-3, 1e3)) * RBF(1.0, (1e-2, 1e2))
gp = GaussianProcessRegressor(kernel=kernel, n_restarts_optimizer=10)

# 모델 피팅
gp.fit(X, y)

# 새로운 데이터 포인트에서 예측
x_pred = np.atleast_2d(np.linspace(0, 5, 1000)).T
y_pred, sigma = gp.predict(x_pred, return_std=True)

# 결과 시각화
import matplotlib.pyplot as plt

plt.figure()
plt.scatter(X, y, c='k', label='데이터')
plt.plot(x_pred, y_pred, 'r', label='예측값')
plt.fill_between(x_pred[:, 0], y_pred - 1.96 * sigma, y_pred + 1.96 * sigma, alpha=0.2, color='r', label='95% 신뢰구간')
plt.xlabel('X')
plt.ylabel('y')
plt.legend(loc='best')
plt.show()

 

LGBM

- 베이스라인 예시코드대로 LGBM을 돌리면 기본 점수로 약 53점 정도를 받을 수 있는 것으로 보였습니다. 그러다가 기본 코드에 수업에서 배운 하이퍼파라미터만 조금 수정해 주니 점수가 30점대로 가는 것을 파악했습니다. 일단은 원초적인 방법으로 여러 가지 값들을 넣어서 스코어를 얻어보는 과정을 수행해 보다가 optuna를 사용해서 적절한 하이퍼파라미터값을 찾는 것을 돌려 보았습니다. 그런데 깊은 학습을 하기 위해서는 생각보다 오래 걸리고 평가 지표 점수도 점차 머물러 있는 경향을 보였습니다.

# 사용한 하이퍼파라미터

num_leaves: 결정 트리의 최대 리프 노드 수. 큰 값은 모델의 복잡성을 증가시킬 수 있습니다.

max_depth: 트리의 최대 깊이를 제한합니다. num_leaves 대신 사용할 수 있습니다.

learning_rate (또는 eta): 각 트리에서 얼마나 많은 정보를 사용할 것인지를 제어하는 학습률입니다.

n_estimators: 생성할 트리(추정자)의 수, 즉 부스팅 라운드의 횟수입니다.

min_child_samples: 리프 노드에 필요한 최소 샘플 수입니다. Overfitting 방지를 위해 조정할 수 있습니다.

colsample_bytree: 각 트리를 학습할 때 사용할 피처의 비율을 나타내는 하이퍼파라미터입니다.

random_state: 랜덤 시드 값으로, 모델을 재현 가능하게 만들기 위해 사용됩니다.
# optuna 예시 코드

from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor
from lightgbm.sklearn import LGBMClassifier, LGBMRegressor
# KFold(CV), partial : optuna를 사용하기 위함
from sklearn.model_selection import KFold
from functools import partial
# hyper-parameter tuning을 위한 라이브러리, optuna
import optuna

def optimizer(trial, X, y, K):
    # 조절할 hyper-parameter 조합을 적어줍니다.
    num_leaves = trial.suggest_categorical('num_leaves', [128, 256] ) # Grid Search
    max_depth = trial.suggest_int('max_depth', 7, 9)
    learning_rate = trial.suggest_float('learning_rate', 0.01, 0.1)
    n_estimators = trial.suggest_int( 'n_estimators', 50, 500)


    # 원하는 모델을 지정합니다, optuna는 시간이 오래걸리기 때문에 저는 보통 RF로 일단 테스트를 해본 뒤에 LGBM을 사용합니다.
    model = LGBMRegressor(num_leaves=128,
                          max_depth=7,
                          learning_rate=learning_rate,
                          n_estimators=n_estimators,
                          random_state=42)

    # K-Fold Cross validation을 구현합니다.
    folds = KFold(n_splits=K)
    losses = []

    for train_idx, val_idx in folds.split(X, y):
        X_train = X.iloc[train_idx, :]
        y_train = y.iloc[train_idx]

        X_val = X.iloc[val_idx, :]
        y_val = y.iloc[val_idx]

        model.fit(X_train, y_train)
        preds = model.predict(X_val)
        loss = mean_absolute_error(y_val, preds)
        losses.append(loss)


    # K-Fold의 평균 loss값을 돌려줍니다.
    return np.mean(losses)

 

[마무리]

 오늘은 본격적으로 모델링 작업을 시작했습니다. 일단은 베이스라인 코드를 활용해서 수정하는 방법으로 평가에 접근하는 것을 목표로 했습니다. 머신러닝 프로젝트를 하면서 느끼는 점은 결과를 기다리는데 생각보다 시간이 오래 걸린다는 것을 알게 되었습니다. 또 데이콘에 작업물을 제출하는 것도 3회로 제한이 되어 있어서 정확한 결과를 바로바로 확인하지 못하는 것도 아쉬운 점인 거 같습니다. 또 베이스 라인 코드만을 이용해서는 더 좋은 결과를 얻지 못하는 것도 알게 되었습니다. 내일부터는 새로운 방법을 찾아보는 것도 좋을 거 같습니다.

반응형

댓글