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

[AI 부트캠프] DAY 57 - 머신러닝 프로젝트 1

by HOHHOH 2023. 10. 12.

[오늘의 일지]

머신러닝 프로젝트 - 조편성, 주제선정, 대회 파악하기, 데이터 파악하기, 베이스라인 

[상세 내용]

머신러닝 프로젝트

조편성

- 조편성은 기존 프로젝트에서는 선호도를 조사해서 랜덤 하게 편성되는 구조를 가지고 있었는데 이번에는 사전에 마음이 맞는 사람끼리 조를 미리 구성해도 된다고 공지를 해줬습니다. 저는 처음에는 그냥 새로운 사람들과 그냥 해보자는 생각이었는데 마침 감사하게도 전에 EDA 프로젝트를 같이했던 조원분께서 먼저 이번에도 같이 해보자고 권해주셔서 두 명이서 같이 하게 되었습니다. 지난 프로젝트 때 좋은 경험을 했기 때문에 이번 조편성도 기분 좋게 출발할 수 있었던 거 같습니다.

 

주제선정

- 주제는 총 6개가 있었습니다. 캐글 대회 3개와 데이콘 대회 3였는데 캐글에서는 현재 진행되고 있는 대회가 2개였고 데이콘은 1개가 있었습니다. 강사님께서 현재 진행되고 있는 대회를 선택하는 것이 프로젝트를 위해서 동기부여가 잘 된다고 말씀하셔서 저희 조는 현재 진행되고 있는 대회로 간추려서 선택지를 3개로 줄였습니다. 그리고 캐글 대회의 경우는 기간이 굉장히 긴 대회들만 있었고 데이콘이 기간이 비교적 짧아서 결과도 금방 나올 거 같다는 생각이 들어서 신청하게 되었습니다. 그렇게 선택하게 된 대회의 주제 '선박 정보를 기반으로 선박의 대기 시간 예측하기'로 HD한국조선해양에서 주관하고 있는 대회였습니다. 자세한 정보는 아래에 링크를 남기겠습니다.

 

HD현대 AI Challenge - DACON

분석시각화 대회 코드 공유 게시물은 내용 확인 후 좋아요(투표) 가능합니다.

dacon.io

 

대회 파악하기

- 데이터를 제공하는 이유에 대해서 간략하게 설명하자면 코로나19가 끝난 후로 선박을 통한 물류들이 많아지면서 항만에서 대기하는 선박들이 많아졌다고 합니다. 그래서 여러 가지 데이터를 제공해서 대기 시간을 예측하는 AI 알고리즘 모델을 구축하는 것을 큰 목표로 두고 있다고 합니다. 결론적으로 저희가 구해야 하는 타깃은 대기시간이고 다양한 데이터의 피처들을 이용해서 구해야 하며 평가지표와의 차이에 따라서 점수를 매기고 순위를 정하는 구조였습니다. 여기서 강사님이 말씀해 주신 동기부여라는 것이 실시간으로 순위를 올리는 부분에서 동기부여가 된다는 것을 느꼈습니다.

 

데이터 파악하기

- 대회의 주제를 보면 알 수 있듯이 데이트는 조선해양과 관련되어 있었습니다. 아래에 피처들에 대해서 자세하게 나와있는데 몇몇의 피처들은 object형식으로 인코딩이 필요한 것을 파악할 수 있었습니다.

Feature Name Description
ARI_CO 도착항의 소속국가(도착항 앞 2글자)
ARI_PO 도착항의 항구명(도착항 뒤 글자)
SHIP_TYPE_CATEGORY 선종 통합 바탕으로 5대 선종으로 분류
DIST 정박지(ber_port)와 접안지 사이의 거리
ATA anc_port에 도착한 시점의 utc. 실제 정박 시각(Actual Time of Arrival)
ID 선박식별 일련번호
BREADTH 선박의 폭
BUILT 선박의 연령
DEADWEIGHT 선박의 재화중량톤수
DEPTH 선박의 깊이
DRAUGHT 흘수 높이
GT 용적톤수(Gross Tonnage)값
LENGTH 선박의 길이
SHIPMANAGER 선박 소유주
FLAG 선박의 국적
U_WIND 풍향 u벡터
V_WIND 풍향 v벡터
AIR_TEMPERATURE 기온
BN 보퍼트 풍력 계급
ATA_LT anc_port에 도착한 시점의 현지 정박 시각(Local Time of Arrival)(단위 : H)
DUBAI 해당일의 두바이유 값
BRENT 해당일의 브렌트유 값
WTI 해당일의 WTI 값
BDI_ADJ 조정된 벌크운임지수
PORT_SIZE 접안지 폴리곤 영역의 크기
CI_HOUR 대기시간

 

베이스라인 

- 프로젝트를 시작하기 전에 강사님께서 대회에서 주어지는 베이스라인 코드나 캐글 같은 경우는 사람들이 먼저 구축해 놓은 템플릿 코드를 이용하는 것이 좋다고 말씀해 주셨는데 이번 대회도 역시 데이콘에서 베이스 코드를 제공해 주고 있었습니다. 베이스 코드에 대해서 설명하자면 ATA라는 피처의 연도, 날짜, 시간, 분, 주까지 분리를 해주었고 object파일들의 인코딩까지 해주었으며 결측치도 간단하게 평균값으로 대체해 주면서 전처리를 모두 해줬습니다. 그리고 퓨처 importance를 통해서 피처의 중요도를 정해주고 스레드홀드를 통해서 과감하게 피처들을 drop 시켜서 K-FoldK-Fold Model Fitting & Validation 과정까지 마무리하면 큰 틀을 정해준 거 같았습니다. 당연하게도 평가지표는 매우 기본적으로 나와 있습니다.

# Import & Data Load

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import lightgbm as lgb
import bisect
from tqdm import tqdm
from sklearn.metrics import mean_absolute_error
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import KFold

train = pd.read_csv('train.csv').drop(columns=['SAMPLE_ID'])
test = pd.read_csv('test.csv').drop(columns=['SAMPLE_ID'])

# Data Pre-processing

# datetime 컬럼 처리
train['ATA'] = pd.to_datetime(train['ATA'])
test['ATA'] = pd.to_datetime(test['ATA'])

# datetime을 여러 파생 변수로 변환
for df in [train, test]:
    df['year'] = df['ATA'].dt.year
    df['month'] = df['ATA'].dt.month
    df['day'] = df['ATA'].dt.day
    df['hour'] = df['ATA'].dt.hour
    df['minute'] = df['ATA'].dt.minute
    df['weekday'] = df['ATA'].dt.weekday

# datetime 컬럼 제거
train.drop(columns='ATA', inplace=True)
test.drop(columns='ATA', inplace=True)

# Categorical 컬럼 인코딩
categorical_features = ['ARI_CO', 'ARI_PO', 'SHIP_TYPE_CATEGORY', 'ID', 'SHIPMANAGER', 'FLAG']
encoders = {}

for feature in tqdm(categorical_features, desc="Encoding features"):
    le = LabelEncoder()
    train[feature] = le.fit_transform(train[feature].astype(str))
    le_classes_set = set(le.classes_)
    test[feature] = test[feature].map(lambda s: '-1' if s not in le_classes_set else s)
    le_classes = le.classes_.tolist()
    bisect.insort_left(le_classes, '-1')
    le.classes_ = np.array(le_classes)
    test[feature] = le.transform(test[feature].astype(str))
    encoders[feature] = le

# 결측치 처리
train.fillna(train.mean(), inplace=True)
test.fillna(train.mean(), inplace=True)

# 모델 학습 및 특성 중요도 확인

def train_and_evaluate(model, model_name, X_train, y_train):
    print(f'Model Tune for {model_name}.')
    model.fit(X_train, y_train)
    
    feature_importances = model.feature_importances_
    sorted_idx = feature_importances.argsort()

    plt.figure(figsize=(10, len(X_train.columns)))
    plt.title(f"Feature Importances ({model_name})")
    plt.barh(range(X_train.shape[1]), feature_importances[sorted_idx], align='center')
    plt.yticks(range(X_train.shape[1]), X_train.columns[sorted_idx])
    plt.xlabel('Importance')
    plt.show()
    
    return model, feature_importances

X_train = train.drop(columns='CI_HOUR')
y_train = train['CI_HOUR']

# Model Tune for LGBM
lgbm_model, lgbm_feature_importances = train_and_evaluate(lgb.LGBMRegressor(), 'LGBM', X_train, y_train)

# 특성 중요도로부터 Feature Selection

threshold = 85 # Your Threshold
low_importance_features = X_train.columns[lgbm_feature_importances < threshold]

X_train_reduced = X_train.drop(columns=low_importance_features)
X_test_reduced = test.drop(columns=low_importance_features)


# K-Fold Model Fitting & Validation

lgbm = lgb.LGBMRegressor()

# 5-Fold 설정
kf = KFold(n_splits=5, shuffle=True, random_state=42)

# 각 fold의 모델로부터의 예측을 저장할 리스트와 MAE 점수 리스트
ensemble_predictions = []
scores = []

for train_idx, val_idx in tqdm(kf.split(X_train_reduced), total=5, desc="Processing folds"):
    X_t, X_val = X_train_reduced.iloc[train_idx], X_train_reduced.iloc[val_idx]
    y_t, y_val = y_train[train_idx], y_train[val_idx]
    
    # 두 모델 모두 학습
    lgbm.fit(X_t, y_t)
    
    # 각 모델로부터 Validation set에 대한 예측을 평균내어 앙상블 예측 생성
    val_pred = lgbm.predict(X_val)
    
    # Validation set에 대한 대회 평가 산식 계산 후 저장
    scores.append(mean_absolute_error(y_val, val_pred))
    
    # test 데이터셋에 대한 예측 수행 후 저장
    lgbm_pred = lgbm.predict(X_test_reduced)
    lgbm_pred = np.where(lgbm_pred < 0, 0, lgbm_pred)
    
    ensemble_predictions.append(lgbm_pred)

# K-fold 모든 예측의 평균을 계산하여 fold별 모델들의 앙상블 예측 생성
final_predictions = np.mean(ensemble_predictions, axis=0)

# 각 fold에서의 Validation Metric Score와 전체 평균 Validation Metric Score출력
print("Validation : MAE scores for each fold:", scores)
print("Validation : MAE:", np.mean(scores))

 

[마무리]

 오늘은 이번 머신러닝 프로젝트를 시작하게 되는 초기 과정에 대해서 정리해 보았습니다. 실제로는 베이스라인 코드를 활용해서 많은 시도를 하고 있지만 자세한 것은 차즘차즘 정리해서 써보도록 하겠습니다. 프로젝트를 시작하게 되면서 비로소 머신러닝이라는 것의 정의에 대해서 다시 한번 적립하게 되는 것 같습니다. 제가 느낀 머신러닝이라는 것은 간략하게 말하자면 누가 어떻게 자신만의 코드를 통해서 주어진 평가지표에 더 적합한 모델을 만드느냐였던 거 같습니다. 프로젝트가 끝날 때까지 좋은 모델을 만들기 위해 노력해야겠습니다.

반응형

댓글