자격증/빅데이터분석기사

[빅데이터분석기사] 작업 2유형 작성패턴 - 회귀문제 (2) 시간데이터

Ddolgom 2022. 11. 26. 15:41
반응형

빅데이터 분석기사 시험에서는 회귀 문제중에 시간데이터를 다룰 확률이 높다.

 

사실 강의나 책마다 다루는 경우가 있고 다루지 않는 경우도 있으나, 추가적으로 다루어 보고자 한다.

 

데이터셋의 경우에는 x_train, x_test, y_train이 나누어 지지 않은 경우로 진행도 해보았지만, 실제로 dataq.or.kr 홈페이지에 들어가서 실습환경을 보면 3개의 데이터가 분리되어 있고 최종적으로 y_test값을 제출하는 형식이라서 이번에는 나누어져 있는 데이터로 진행을 해보려고 한다. (실제 실무에서는 이렇게 친절하게 나눠져 있지 않고, 앞으로의 출제 형식 자체도 전체 데이터 하나를 직접 나누어서 해야할 수 도 있을 것 같다.)

 

1. 데이터 read

import pandas as pd
import numpy as np

x_train = pd.read_csv('/content/bike_x_train.csv', encoding = 'cp949')
x_test = pd.read_csv('/content/bike_x_test.csv', encoding = 'cp949')
y_train = pd.read_csv('/content/bike_y_train.csv', encoding = 'cp949')

데이터를 불러왔는데, 앞에서와 같이 실제 화면 출력결과는 생략하고 코드만을 정리한다.

(분석에 꼭 필요한 부분들은 출력 결과를 편의상 넣음)

캐글 홈페이지에 들어가면 바이크 수요 예측(Bike sharing Demand)라는 것을 검색하면 데이터셋을 구할 수 있다.

 

 

2. 데이터의 정보들을 확인을 위한 3종 세트 및 기초작업들

 

# 앞서 진행했던 3종세트

# 1. 행과 열 확인
print(x_train.shape)
print(x_test.shape)
print(y_train.shape)

#2. 각 열들의 데이터 타입 분석
print(x_train.info())

#3. 각 열들의 기술통계값들 확인
print(x_train.describe())

x_train.info() 출력결과

지금 info()함수를 실행해서 나온 데이터를 보면 datetime은 object형태로 되어 있다.

우리가 실제로 datetime 형식으로 변환해주어서 진행을 해야 한다.

 

실제로 문제에서 계절, 공휴일, 근무일, 날씨 같은 경우에는 숫자값으로 되어 있지만, 문제에서는 다음과 같이 주어져 있다.

 

계졀 : 1(봄), 2(여름), 3(가을), 4(겨울)

공휴일 : 1(공휴일), 0(공휴일 아님)

근무일 : 1(근무일), 0(근무일 아님)

날씨 : 1(아주 깨끗한 날씨), 2(안개와 구름이 있는 날씨), 3(약간 눈과 비 또는 천둥이 치는 날씨), 4(아주 많은 비 또는 우박이 내리는 날씨)

 

그래서 문제와 같이 범주형( 라벨 인코딩화 되어 있다고 보면 된다.) 데이터들이 실제로 존재하는지 확인을 할 필요가 있다.

 

print(x_train['계절'].unique())
print(x_train['공휴일'].unqiue())
print(x_train['근무일'].unqiue())
print(x_train['날씨'].unqiue())

확인결과 숫자로 라벨인코딩화 되어 있음을 확인 할 수 있다.

 

그리고 y_train 같은 경우에는 datetime 컬럼이 깨져서 나온다.

글씨가 깨져서 나옴

이런 경우에는 모든 작업이 끝나고 열의 이름을 바꾸거나 할수 있지만, 충분히 혼동을 줄수 있기 때문에 이름을 미리 바꾸어 놓는다.

 

y_train.rename(columns = {'癤풼atetime':'datetime'}, inplace = True)

변수명을 주어서 바꿀수도 있으나, 번거로움 때문에 inplace = True로 설정하여 변경된 값을 저장시킨다.

 

사실, 파이썬과 판다스에서 여러 함수들이 있지만, 헷갈리는 경우중 대표적인 것은 (), {}, [] 소중대괄호의 사용이다.

언제 소괄호를 쓸지 중괄호를 쓸지 헷갈리는 부분들이 가장 사람을 빡치게 하는 경우인데, 많이 사용해보면서 익히는 방법밖에는 답이 없는것 같다.

 

 

3. 독립변수와 종속 변수 합치기

이 과정 같은 경우에는 x_train, y_train이 분리되어 있기때문에 필수적인 작업이다.

독립변수와 종속변수의 상관관계를 파악하기 위해서는 무조건 해야하는 작업으로 다음과 같이 진행한다.

data_check = pd.concat([x_train, y_train], axis = 1)

print(data_check.head())

pandas의 concat함수를 쓰면 데이터들을 열에 맞추어서 붙일수 있다. axis =1은 열에 맞추어 붙이는 것을 뜻하고, axis = 0은 행에 맞추어 붙이는 것을 뜻한다.

여기서 주의해야할 점은 concat함수 사용시에는 '', "" (작은 따옴표나 큰 따옴표)가 들어가지 않는다.

매번 헷갈리는 부분이다. 

 

문제에서 주어진 계절, 공휴일, 근무일, 날씨에 따른 어느 특정날에 많이 빌리는지에 대한 확인이 필요하고 분류문제나 앞에서의 회귀문제처럼 필요없는 컬럼 자체는 삭제를 하는 것이 머신러닝 성능에 훨씬 좋은 성능을 준다.

 

물론 다중공선성 확인도 필요하겠지만, 위의 데이터에서는 굳이 검증을 할 필요는 없어 보인다.

 

왜냐하면 계절과 공휴일,근무일, 날씨 간의 상관성이 보일만한 것이 따로 없기 때문이다. (계절과 날씨는 충분히 상관성이 있어 보이기도 한다. 왜냐하면 여름에 많은 비가 내릴 확률이 높기 때문이다. 하지만, 계졀과 날씨는 따로 분리해서 대여수를 파악해도 그 자체가 유의미하기 때문이다.)

 

4. 독립변수와 종속 변수 관계 확인하기

print(data_check.groupby('계절')['count'].sum())

다음과 같이 groupby 함수를 활용하면 계절에 따른 대여량(count)를 확인할 수 있다.

 

참고할 점은

print(data_check.groupby(['계절'])['count'].sum()) # 기준이 되는 계절열에 소괄호 안에 대괄호를 넣어도 되고 안넣어도 된다.

그루핑을 하는 기준인 계절에 대괄호를 소괄호 사이에 넣어도 되고 안넣어도 된다. 결과는 동일하다.

 

계절을 기준으로 보았을때 3(가을)이 가장 대여량이 많고 1(봄)보다도 대여량이 많음을 알 수 있다. 겨울의 대여량이 가장 적지 않은 것은 고무적인 결과이다.

print(data_check.groupby('공휴일')['count'].sum())
print(data_check.groupby('근무일')['count'].sum())
print(data_check.groupby('날씨')['count'].sum())

나머지 3개의 기준에 대해서도 진행을 해보면,

 

위와 같이 뚜렷한 결과가 나온다.

 

5. 시계열 데이터로 변환하기

datetime 열 같은 경우에는 

다음과 같이 표시가 되어 있지만, object 타입인 관계로 datetime형으로 변환시켜주어야 시계열을 분리할 수가 있다.

x_train['datetime'] = pd.to_datetime(x_train['datetime'])

판다스에 있는 to_datetime을 사용하면 바로 변환이 되는데, 곧바로 년월일 단위로 분리하여 분석을 진행해보자.

x_train['year'] = x_train['datetime'].dt.year

print(x_train['year'].unique())

x_train['month'] = x_train['datetime'].dt.month

print(x_train['month'].unique())

x_train['day'] = x_train['datetime'].dt.day

print(x_train['day'].unique())


x_train['hour'] = x_train['datetime'].dt.hour

print(x_train['hour'].unique())

각각의 결과물을 보면 년, 월, 일, 시간임을 알수 있고 일과 시간은 19일까지 나오고 시간은 23시까지 출력이 되는 것을 알 수 있다.

to_datetime으로 변환을 한후 시간 정보를 추출할때 주의할 점은 dt라는 것을 붙여야 출력이 된다는 것이다.

 

dt.month, dt.day, dt.hour 이런식으로 말이다.

 

x_train['dayofweek'] = x_train['datetime'].dt.dayofweek
print(x_train['dayofweek'].unique())

dayofweek는 요일을 추출하는 키워드인데, 출력을 해보면 숫자로 되어 있다. (라벨 인코딩형식으로 되어 있음을 알 수 있다.)

 

6. 시간 데이터에 따른 대여량 분석하기

 

추가적으로 시간 데이터에 따른 대여량을 분석해보고 필요없는 컬럼들은 삭제를 해서 머신러닝의 성능을 높이려고 한다.

계속 언급을 하지만, 빅데이터 분석기사에서 어느정도 성능을 내라는 문제가 안나오기 때문에, 그냥 넣어도 값은 나오지만, 실무와 향후 시험 문제 스타일의 변경이 될수도 있는 문제이기에 진행을 해보고자 한다.

data_check2 = pd.concat([x_train, y_train], axis = 1) # 새로운 변수에 집어넣어준다.
print(data_check2.groupby('year')['count'].sum()) # 연도별 대여량 분석

print(data_check2.groupby('month')['count'].sum()) # 달별 대여량 분석

print(data_check2.groupby('day')['count'].sum())

일별 데이터로는 거의 대동소이하게 10만개 가량이 나오는데, 뚜렷한 특징이 없다. (삭제할 예정)

 

print(data_check2.groupby('hour')['count'].sum())

 

 

 

 

print(data_check2.groupby('dayofweek')['count'].sum())

요일별 데이터 또한 뚜렷한 특징이 없어서 삭제할 예정이다.

 

7. 불필요한 컬럼 삭제

x_train = x_train.drop(columns = ['dayofweek'])
x_train = x_train.drop(columns = ['day'])

요일과 일별 데이터 이외에는 뚜렷한 차이가 있다.

그래서 그대로 두고, 테스트 데이터 또한 동일하게 컬럼을 맞추어 주어야 한다. (행과 열을 맞추어야 한다. )

그렇지 않게되면, 성능도 안나오고 성능의 결괏값이 나왔다할지라도 신뢰할수 없는 데이터가 된다.

 

# 테스트 데이터도 동일하게
x_test['datetime'] = pd.to_datetime(x_test['datetime'])

x_test['year'] = x_test['datetime'].dt.year
x_test['month'] = x_test['datetime'].dt.month
x_test['hour'] = x_test['datetime'].dy.hour

테스트 데이터는 애초에 불필요한 컬럼 삭제가 필요없고 그냥 위에서 봤던 유의미한 데이터 컬럼들을 추가하는 방식으로 진행을 하면 된다.

 

8. 제출할 컬럼 복사해서 저장해놓기

빅데이터 분석기사 시험에서는 제출양식을 문제에서 써놓는다.

지금 문제 같은 경우에는 datetime열과 count열을 합쳐서 DataFrame양식으로의 제출을 요구하기 때문에 미리 1열의 datetime을 변수에 저장해서 향후 마지막 과정에서 pd.concat으로 붙여서 제출하면 된다.

그래서 이 한줄의 과정이 필요하다.

 

x_test_datetime = x_test['datetime'] # 향후 제출할 형식에 쓰일 열

 

9. 데이터 분리하기

여기까지 진행이 되었으면 데이터를 분할하고 평가하는 것이 필요하다.

다만, 주의를 해야할 부분이 있다. 

초심자나 데이터를 많이 다루어 보지 않았으면, 혼란이 온 상태로 암기한 코드를 그대로 적용하여 데이터의 사이즈가 뒤죽박죽 되거나 짬뽕이 되어 앞서 진행하였던 데이터전처리 과정의 수고가 무색하게 되는 경우가 비일비재하다.

 

우리한테 주어진 데이터는 지금 딱 3개이다.

x_train, y_train, x_test 이고 y_test값은 없다.

 

실질적으로 x_train(문제), y_train(정답)을 머신러닝 모델에 넣어서 훈련 및 학습을 시킨다.

검증용으로 활용을 하는 것으로 실제 모델의 성능이 어떠한지 혹여나 성능이 안나오거나 문제가 생기면 확인을 할수가 있다.

 

보통 k-fold cross-validation의 방식을 사용하지만, 여기에서는 홀드아웃 방식으로서 모든 train 데이터를 분할하여 검증하고 평균을 내는 방식이 아니라는점을 유의해야한다.

 

그래서 train_test_split함수로 나눌때에는 기존의 x_train과 y_train 데이터를 새로운 변수로 분할하는데,

 

4개의 변수들 : X_TRAIN, Y_TRAIN, X_TEST, Y_TEST (편의상 새로운 변수화 시키기 위해 대문자로 지정한다. 파이썬은 대소문자 구별을 하기 때문에 소문자 x_train, y_train, x_test와는 다른 변수가 되는 것이다.)를 변수로 지정하여 기존의 주어진 x_train과 y_train을 4개의 변수들로 나누는 것이다. (홀드아웃 방식으로 검증을 위한 것!)

 

이 예측된 모델결과와 기존의 정답(y_test)와 비교를 하는 것이 정석적인 방법인데, 여기에서는 y_test가 주어지지 않는다.

그렇기에 단순하게  x_test를 모델에 넣어서 결괏값을 최종적으로 제출해야 하는 것으로 끝내는 것이 수험생의 몫이다.

 

from sklearn.model_selection import train_test_split

X_TRAIN, X_TEST, Y_TRAIN, Y_TEST = train_test_split (x_train, y_train, test_size = 0.2)
# stratify 지정은 분류모델이 아니라서 생략, train : test 비율은 8:2로 설정

print(X_TRAIN.shape)
print(X_TEST.shape)
print(Y_TRAIN.shape)
print(Y_TEST.shape)

10. 모델 학습하기

from lightgbm import LGBMRegressor

model = LGBMRegressor()

model.fit(X_TRAIN, Y_TRAIN)

pred = model.predict(X_TEST)

여타 다른 회귀모형들도 많으나, LightGBM으로 진행을 하였다.

 

import를 하고 객체 생성후에 fit함수에다가 데이터 분할을 진행하였던, X_TRAIN, Y_TRAIN을 넣고 predict함수로 X_TEST를 넣어서 최종적으로 예측된 값을 pred라는 변수에 저장하였다.

 

11. 하이퍼 파라미터 튜닝 (optional한 부분)

하이퍼 파라미터 튜닝은 시험 범위에는 들어가지만, 직접적으로 하이퍼파라미터 튜닝 사용 문제가 나온적이 없기 때문에 옵션으로 진행을 하면 된다.

from sklearn.model_selection import GridSearchCV

params = {'n_estimators': [50, 100], 'max_depth' : [4, 6]}

model2 = LGBMRegressor()

clf = GridSearchCV(estimator = model2, param_grid = params, cv = 3)

clf.fit(X_TRAIN, Y_TRAIN)

print(clf.best_params_)

사실 param_grid 하이퍼파라미터에 넣어줄 변수들은 n_estimators와 max_depth 이외에도 엄청나게 많으나, 파일을 read하여 모델 결과 출력까지 1분이내여야한다는 점을 고려하면 저정도면 충분하다고 보여진다.

그리고 그리드 서치이외에 랜덤서치나 베이지안 최적화의 시간은 1분을 초과하는 경우가 대부분이여서 그리드서치로 진행을 하게 된다. 가장 best가 나온값은

 

이러한 형태로 넣어서 다시 재학습시켜주면, 소폭 향상된 결과를 볼수 있다. 

 

12. 모델 평가하기

from sklearn.metrics import r2_score

y_pred = pd.DataFrame(model.predict(X_TEST)).rename(columns = {0:'count'})


print(r2_score(Y_TEST, y_pred)) # 실제값인 Y_TEST먼저 그다음에 y_pred(예측값) **순서주의

문제에서는 모델 평가지표가 주어지는데, 여기에서는 r2 회귀계수 지표로 평가하라고 주어져 있다.

sklearn안에 metrics 모듈에서의 r2_score를 import를 하고, X_TEST로 평가하기 위해 predict함수에 넣어주면 y 예측값이 나오는데, y_pred라는 변수로 저장을 하고, predict()함수로 추출된 결과는 데이터프레임의 형태가 아니라서 반드시 pd.DataFrame의 함수를 사용하여 바꾸어주어야 실제 제출하고자 할때 사용되는 pd.concat함수에 들어가서 제출 형식은 2열로 표현을 할수 있게 된다.

 

predict()함수를 쓰면 열의 이름이 0이 되는데 이또한 문제에서 요구하는 count열로 이름변경을 하여야 하므로 다음과 같이 코드를 작성하고 r2_score(Y_TEST, y_pred)로 순서가 헷갈리지 않게 입력하여야 한다.

 

Y_TEST같은 경우에는 실제값이고 y_pred 변수에 담긴 데이터는 예측값인데, 실제값과 예측값의 상대적 비교를 통해 모델의 성능을 도출하게 된다.

 

앞서 언급했던 홀드아웃 기법으로 모델의 성능이 좋은지 평가를 하고 우리에게 애시당초 주어진 x_test(소문자).csv 파일을 모델에 넣고 나온 숫자결과를 합쳐서 제출하면 끝이다.

 

x_train, y_train에서 유래한 데이터로 검증을 진행하였는데, 94%로 높은 성능이 나왔다.

 

여기서 검증이 끝났기에 추가적으로 해야할 것은 우리에게 애시당초 주어진 x_test의 데이터로 predict를 해야한다는 것!

X_TEST로 그냥 제출을 해버리면 데이터의 길이가 짧아서 높은 성능이 나오지 않고, 데이터 맨 밑에 부분은 NAN (결측값)으로 나와서 엄청난 감점이 될 것이다.

 

y_pred2 = pd.DataFrame(model.predict(x_test)).rename(columns = {0:'count'})

새로운 y_pred2를 생성하여 앞에서 진행했던 동일한 과정을 거치면 된다. (x_test임에 주의, X_TEST아님!!)

 

이제 dataframe 1열짜리 2개를 합쳐서 제출하면 끝이다.

 

13. 파일 제출하기 (그리고 확인!!)

이 부분에서 감점이 되는 사람이 많다고 들었다. 여러 책들과 강의를 통해서 충분히 그럴수 있다는 생각이 든다.

final = pd.concat([x_test_datetime, y_pred2], axis =1 )

final.to_csv('/content/00100.csv', index=False)

final_check = pd.read_csv('/content/00100.csv')

print(final_check)

final 변수에 두 데이터프레임 데이터를 합치고 최종적으로 to_csv()함수를 통해서 csv파일을 생성시키면되는데, 

 

1. 지정된 경로에 저장

2. 수험번호로 csv파일을 만들기 (위에서는 00100이 가상의 수험번호로 쓰였다.)

3. index = Fasle로 지정해야 2열이 나온다.

 

이 3가지를 주의 하여야 한다.

특히, 3번은 index=True인 default값으로 열이 하나가 더 자동으로 생성되면 3열이 되어 채점자체가 사람이 하는것이 아니다보니 프로그램 알고리즘상 0점이 될수도 있다. 무조건 주의해야하는 부분이다.

 

그리고 마지막으로 final_check변수를 만들어 생성된 데이터(최종 제출 데이터)를 read_csv()함수로 읽어서 열의 이름이 제출형식과 같은지, 결측된 부분이 없는지, 잘못된 형식으로 되어 있지 않은지를 최종적으로 확인하면 비로소 끝이 난다.

최종 제출 파일

기본적으로 유형2는 1문제만 출제되는데 40점의 배점인 만큼 결코 그냥 넘겨서는 안되는 부분이다.

비지도학습이 나올지는 모르겠으나, 기본적으로 지도학습의 출제 경향성이 지켜질 것 같고, 실무에서도 정형데이터를 활용해서 머신러닝을 하는 부분이 아직까지도 많이 쓰이는 만큼 반복 숙달을 하고 코드를 외우되 상황에 맞게 조금씩 변형할수 있는 실력이 있어야 합격권안에 들어갈 것 같다.

 

라벨인코딩이나 원핫인코딩 같은 부분은 이번 예시에서는 생략이 되었는데, 필요할때 적재적소에 쓰면 된다.

 

아직 내공이 부족해서인지는 모르겠으나, 빅데이터분석기사 실기 공부를 하면서 부족했던 판다스의 실력이나 모델링 부분에서의 원리를 제대로 파악할수 있었는데, 주변에서 데이터사이언티스트나 머신러닝 개발자가 되려는 비전공자나 초심자는 무조건 거쳐가는 것이 좋다고 생각한다.

 

혹여나, 데이터셋이 필요하거나 모든 코드의 출력결과를 게시하지 않아 궁금한 사항이 있으면 리플을 달아주시면 답변해드릴예정이다.

 

 

반응형