KT Aivle 5기/프로젝트
[KT AIVLE SCHOOL] KT Aivle 5차 미니프로젝트 후기 1
G허니
2024. 5. 12. 21:08
5차 미니프로젝트에서는 시계열 데이터를 활용한 상품 판매량 예측 모델링을 진행했습니다.
EDA 탐색적 분석
중요 범줏값의 비율을 확인합니다.
각 범주별 판매량 및 판매량 추이등을 확인 했습니다.
두 범주별 판매량 추이를 이용해 판매량을 선그래프로 시각화해 시계열 패턴을 찾았습니다.
diff()함수를 사용해 변수에 대한 변화량을 확인할 수 있습니다.
데이터프레임 구성
- 기본 변수 구성
- 날짜 변수에서 요소 추출
- 데이터 전처리
- 결측치 처리
- 범주형 데이터의 가변수화
- 데이터 분할(학습용, 검증용)
# datetime 형으로 변환
sales['Date'] = pd.to_datetime(sales['Date'] )
oil_price['Date'] = pd.to_datetime(oil_price['Date'] )
orders['Date'] = pd.to_datetime(orders['Date'] )
# 각 데이터의 기본 정보를 확인
data_list = [sales, orders, oil_price, stores, products]
data_name = ['sales', 'orders', 'oil_price', 'stores', 'products']
for data, name in zip(data_list, data_name):
print('*' * 50)
print('[--------------------', name, '--------------------]')
print(data.info())
print('*' * 50)
for data, name in zip(data_list, data_name):
print('[--------------------', name, '--------------------]')
display(data.describe())
# 데이터셋 전처리 함수
def create_data(pid, sid=44):
lead = products[products['Product_ID'] == pid]
lead = lead['LeadTime'].iloc[0]
df = sales[(sales['Store_ID'] == sid) & (sales['Product_ID'] == pid)]
# Qty 0 삭제
df = df[df['Qty'] != 0]
# orders merge
temp = orders[orders['Store_ID'] == sid].drop('Store_ID', axis=1)
df = pd.merge(df, temp, on='Date', how='left')
# Weekday, Month 추가
df['Weekday'] = df['Date'].dt.day_name()
df['Month'] = df['Date'].dt.month
# oil_price merge
temp = oil_price.copy()
temp['WTI_Price'] = temp['WTI_Price'].rolling(14, min_periods=1).mean()
df = pd.merge(df, temp, on='Date', how='left')
df['WTI_Price'].interpolate(method='linear', inplace=True)
# Target 추가
df['Target'] = df['Qty'].shift((-1)*lead)
# ID열 삭제
df.drop(['Store_ID', 'Product_ID'], axis=1, inplace=True)
#결측치 제거
df.dropna(inplace=True)
df.reset_index(drop=True, inplace=True)
return df
데이터프레임 구성 및 모델링
- 데이터 탐색을 바탕으로 변수 추가
- Linear Regression으로 모델링
- 모델 성능 평가 및 기록
# Linear 모델
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error, mean_absolute_percentage_error
def create_linear(data):
x = data.drop(['Date', 'Target'], axis=1)
y = data['Target']
weekday = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
x['Weekday'] = pd.Categorical(x['Weekday'], categories=weekday)
month = [str(i) for i in range(1, 13)]
x['Month'] = pd.Categorical(x['Month'], categories=month)
x = pd.get_dummies(x, drop_first=True, dtype=int)
x_train, x_val, y_train, y_val = train_test_split(x, y, test_size=4*30, shuffle=False, random_state=1)
model = LinearRegression()
model.fit(x_train, y_train)
y_pred = model.predict(x_val)
print('RMSE:', mean_squared_error(y_val, y_pred, squared=False))
print('MAE:', mean_absolute_error(y_val, y_pred))
print('MAPE', mean_absolute_percentage_error(y_val, y_pred))
print('R2:', r2_score(y_val, y_pred))
plot_model_result(y_train, y_val, y_pred)
return model
함수를 통해 생성된 데이터셋으로 Linear Regression 진행
앙상블 모델 생성
- Random Forest, LightGBM 사용
- RMSE, MAE, MAPE, R2_Score로 성능 평가
- 결과 기록 및 시각화
# 랜던포레스트 모델
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error, mean_absolute_percentage_error
def create_rf(data):
x = data.drop(['Date', 'Target'], axis=1)
y = data['Target']
weekday = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
x['Weekday'] = pd.Categorical(x['Weekday'], categories=weekday)
month = [str(i) for i in range(1, 13)]
x['Month'] = pd.Categorical(x['Month'], categories=month)
x = pd.get_dummies(x, drop_first=True, dtype=int)
x_train, x_val, y_train, y_val = train_test_split(x, y, test_size=4*30, shuffle=False, random_state=1)
model = RandomForestRegressor()
model.fit(x_train, y_train)
y_pred = model.predict(x_val)
print('RMSE:', mean_squared_error(y_val, y_pred, squared=False))
print('MAE:', mean_absolute_error(y_val, y_pred))
print('MAPE', mean_absolute_percentage_error(y_val, y_pred))
print('R2:', r2_score(y_val, y_pred))
plot_model_result(y_train, y_val, y_pred)
return model
# LGBM 모델
from lightgbm import LGBMRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error, mean_absolute_percentage_error
def create_lgb(data):
x = data.drop(['Date', 'Target'], axis=1)
y = data['Target']
weekday = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
x['Weekday'] = pd.Categorical(x['Weekday'], categories=weekday)
month = [str(i) for i in range(1, 13)]
x['Month'] = pd.Categorical(x['Month'], categories=month)
x = pd.get_dummies(x, drop_first=True, dtype=int)
x_train, x_val, y_train, y_val = train_test_split(x, y, test_size=4*30, shuffle=False, random_state=1)
model = LGBMRegressor()
model.fit(x_train, y_train)
y_pred = model.predict(x_val)
print('RMSE:', mean_squared_error(y_val, y_pred, squared=False))
print('MAE:', mean_absolute_error(y_val, y_pred))
print('MAPE', mean_absolute_percentage_error(y_val, y_pred))
print('R2:', r2_score(y_val, y_pred))
plot_model_result(y_train, y_val, y_pred)
return model
하이퍼파라미터 튜닝
- 튜닝을 통한 성능 향상 시도 ( GridSearchCV를 사용해 성능 최적화 진행)
- 최적의 모델 선정
def create_rf(x_train, x_val, y_train, y_val):
params = {'max_depth':range(5, 24), 'n_estimators':range(5, 26)}
model = GridSearchCV(
RandomForestRegressor(random_state=1),
n_jobs=-1,
param_grid=params,
scoring='r2',
cv=5,
).fit(x_train, y_train)
y_pred = model.best_estimator_.predict(x_val)
temp = pd.Series(model.best_estimator_.feature_importances_, index=x_train.columns).sort_values(ascending=False)
plot_model_result(y_train, y_val, y_pred)
print(*model.best_params_.items())
print('예측 정확도:', model.best_score_)
print('RMSE:', mean_squared_error(y_val, y_pred, squared=False))
print('MAE:', mean_absolute_error(y_val, y_pred))
print('MAPE', mean_absolute_percentage_error(y_val, y_pred))
print('R2:', r2_score(y_val, y_pred))
plt.figure(figsize=(15, 5))
sns.barplot(x=temp, y=temp.index)
plt.show()
return model.best_estimator_, y_pred
GridSearchCV를 사용해 성능 최적화 진행
def create_lgb(x_train, x_val, y_train, y_val):
# LGBMRegressor 모델 생성
model = LGBMRegressor()
# 튜닝할 하이퍼파라미터 그리드 설정 {'learning_rate': 0.2, 'max_depth': 3, 'min_child_samples': 15, 'n_estimators': 100}
param_grid = {
'n_estimators': list(range(30,40,1)), # 결정 트리 개수
'learning_rate': [0.1, 0.2, 0.3], # 학습률
'max_depth': [3,5,7,9], # 트리의 최대 깊이
'min_child_samples': list(range(13,24,1)) # 리프 노드의 최소 데이터 수
}
# GridSearchCV를 사용하여 하이퍼파라미터 튜닝
grid_search = GridSearchCV(estimator=model, param_grid=param_grid,
cv=3, n_jobs=-1, scoring='r2') # scoring='neg_mean_squared_error'
grid_search.fit(x_train, y_train)
# 최적의 하이퍼파라미터 출력
print("Best Parameters:", grid_search.best_params_)
# 최적의 모델로 예측 수행
y_pred = grid_search.best_estimator_.predict(x_val)
# 성능 지표 출력
print('RMSE:', mean_squared_error(y_val, y_pred, squared=False))
print('MAE:', mean_absolute_error(y_val, y_pred))
print('MAPE', mean_absolute_percentage_error(y_val, y_pred))
print('R2:', r2_score(y_val, y_pred))
# plot_model_result 함수가 정의되어 있다고 가정합니다.
plot_model_result(y_train, y_val, y_pred)
# 최적의 모델과 예측값 반환
return grid_search.best_estimator_, y_pred
데이터 파이프라인 함수 구현
- 전처리 과정 자동화 함수 구현
- Input: Raw 데이터
- Output: 예측 및 성능 평가 가능한 데이터
데이터 전처리, 탐색, 모델링, 하이퍼파라미터 튜닝 등 전반적인 머신러닝/딥러닝 프로세스를 경험할 수 있었던 좋은 기회였던 것 같습니다.
아쉬었던 부분은 시계열 데이터의 경우 shuffle이나 random sampling을 하게 되면 데이터의 시간순서가 뒤섞이기 때문에 모델이 패턴과 트렌드를 제대로 학습하지 못할 수 있습니다. 이 부분을 간과하고 진행하다 보니 프로젝트가 더 어렵고 힘들었을 것이라 생각됩니다.
그리고 데이터 파이프라인 함수를 직접 구현해보면서 raw 데이터를 모델이 사용 가능한 형태로 가공하는 일련의 과정을 체계적으로 정리해보신 것이 인상 깊었습니다.