*본 내용은 시계열데이터 강의 내용 중 일부분을 요약한 내용입니다
시계열 변수 추출 7종
Feature Engineering 통해 새 변수를 창출
추가된 새 변수가 무조건 종속변수에 영향을 못 줄수도 있다
예로들어 광고비 1,2,3,4(백만원 단위), GDP 1,2,3,4(조 단위) 변수가 있을때 컴퓨터는 이 두 변수를 같은 것으로 취급한다
1. 빈도(Frequency): 계절성 패턴(seasonality)이 나타나기 전까지의 데이터 갯수(사람이 정함)
사람이 정하는 것은 데이터를 년단위로 짜를건지, 시간단위로 짜를 건지 등 을 말한다
예로들어 한 컬럼의 데이터가 2019,2020,2021 있을때, 사람은 연도라는 걸 알지만 컴퓨터는 지정하지 않으면 모르므로
년도라고 지정 해줘야 한다
다만, 데이터를 분석할때 년도,월,일 등 분해 해서 알아봐야 한다-> 어떤 변수가 종속변수에 영향을 줄지는 해보지 않곤 모른다. 이 분해 과정에서 생기는 nan는 여러 방법으로 채울수가 있다.
*빈도를 먼저 설정 시 장점
Freq를 만일 년도로 설정하고 월,일 등으로 날짜를 분해할때, 중간에 누락된 공백을 찾아서 nan로 넣어주고, 분석자는 nan를 채워주면 중간에 빠짐없이 데이터를 채울수 있다
ex) 2020-03-29~ 2021-03-29 데이터에서 일별로 분해 시, 본 데이터에서 누락된 2020-09-21 데이터가 nan로 채워지 게 된다. 이를 위 method로 해결
2.추세(Trend): 시계열이 시간에 따라 증가, 감소 또는 일정 수준을 유지하는 경우
3.계절성(Seasonality): 규칙적인 기간 동안에 나타나는 패턴을 말합니다. 연간,월간,일간,시간 등 반복되는 규칙만 존재한다면 계절성으로 불립니다.
4.주기(Cycle): 일정하지 않은 빈도로 발생하는 패턴
현실 데이터는 계절성과 주기의 명확한 구분이 어렵다(혼재 되어 있는 경우가 많다)
영업 환경이나 전략 변화에 의하여 나타나는 경우가 많다.
5.시계열 분해(추세/계절성/잔차): 본래 데이터를 추세,계절성,잔차로 분해가 가능하다
본래데이터(observed)= 추세(trend) + 계절성(seasonal)+ 잔차(residual)
6.더미변수(Dummy variables): 이진수(0 또는 1)의 형태로 변수를 생성하는 것으로 휴일,이벤트,캠페인 등을 생성 가능
1. 더미변수를 하지 않았을때 의미
Y=ax가 있을때 Y는 매출, X는 계절(봄,여름,가을,겨울 )
a 계수가 3이라고 한다면 계절이 바뀔때마다 3씩 매출에 영향을 준다 로 해석가능하다
즉, 계절이 변할때 마다 매출이 어떻게 변하는지를 알고자 할때 더미 변수를 하지 않고 사용하는게 적합하다
2. 더미변수를 사용하고자 할때 의미
각 계절별로 '따로따로' 매출에 얼마큼 영향을 주는지 알고자 할때 쓰인다
7.지연값(Lagged values): 변수의 지연된 값을 독립변수로 반영하는 것으로,ARIMA/VAR/NNAR 등이 활용
ex) 광고비를 투입한 시점부터 매출에 영향을 준 걸까? 라는 의문점에서부터 시작된다
즉 영향을 주고 받는 시간 차이가 발생한다.
★위 이론 내용을 토대로 실습 진행
Dataset: BikeSharingDemand
Import
# Ignore the warnings
import warnings
# warnings.filterwarnings('always') #항상 경고문이 뜨게 한다
warnings.filterwarnings('ignore') # 경고 뜨지 않게 설정
# System related and data input controls
import os
# Data manipulation and visualization
import pandas as pd
pd.options.display.float_format = '{:,.2f}'.format #options클래스 안에 display 안에 float_format
pd.options.display.max_rows = 10 #전체데이터에서 row data 앞에 5개, 뒤에 5개 만 보이게 함
pd.options.display.max_columns = 20
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# Modeling algorithms
# General
import statsmodels.api as sm
from scipy import stats
# Model selection
from sklearn.model_selection import train_test_split
# Evaluation metrics
# for regression
from sklearn.metrics import mean_squared_log_error, mean_squared_error, r2_score, mean_absolute_error
#데이터 불러오기
location = './Data/BikeSharingDemand/Bike_Sharing_Demand_Full.csv' #맨 앞에 . 점은 동일한 위치 라는 의미
raw_all = pd.read_csv(location)
raw_all
Feature Engineering: 데이터에서 시계열패턴 추출하기
Feature engineering 하기 전/후 비교하기 위해서 non_feature_engineering을 추가해여 생성합니다
def non_feature_engineering(raw):
raw_nfe= raw.copy()
#객체 타입인 datatime 변수를 datetime 타입으로 변경
if 'datetime' in raw_nfe.columns:
raw_nfe['datetime'] = pd.to_datetime(raw_nfe['datetime'])
raw_nfe['DateTime]= pd.to_datetime(raw_nfe['datetime']) #인덱스로 적용
if raw_nfe.index.dtype=='int64':
raw_nfe.set_index('DateTime', inplace=True)
#bring back
#if raw_nfe.dtype !='int64':
# raw_nfe.reset_index(drop=False, inplace=True)
#시간 단위로 시간 축 설정후 결측치는 forward fill
raw_nfe = raw_nfe.asfreq('H', method ='ffill')
return raw_nfe
def feature_engineering(raw):
raw_fe=raw.copy()
if 'datetime' in raw_fe.columns:
raw_fe['datetime'] = pd.to_datetime(raw_fe['datetime'])
raw_fe['DateTime]= pd.to_datetime(raw_fe['datetime']) #인덱스로 적용
if raw_fe.index.dtype=='int64':
raw_fe.set_index('DateTime', inplace=True)
#시간 단위로 시간 축 설정후 결측치는 forward fill
raw_fe = raw_fe.asfreq('H', method ='ffill')
#시계열 분해_추세
result= sm.tsa.seasal_decompose(raw_fe['count'], model ='additive')
Y_trend = pd.DataFrame(result.trend)
Y_trend.fillna(method='ffill', inplace=True)
Y_trend.fillna(method='bfill', inplace=True)
Y_trend.columns = ['count_trend']
#시계열 분해_계절성
Y_seasonal = pd.DataFrame(result.seasonal)
Y_seasonal.fillna(method='ffill', inplace=True)
Y_seasonal.fillna(method='bfill', inplace=True)
Y_seasonal.columns = ['count_seasonal']
#원본과 합치기
pd.concat([raw_fe, Y_trend,Y_seasonal], axis=1).isnull().sum()
if 'count_trend' not in raw_fe.columns:
raw_fe = pd.concat([raw_fe, Y_trend, Y_seasonal], axis=1)
#이동평균으로 일별, 주별 count 생성
Y_count_Day = raw_fe[['count']].rolling(24).mean()
Y_count_Day.fillna(method='ffill', inplace=True)
Y_count_Day.fillna(method='bfill', inplace=True)
Y_count_Day.columns = ['count_Day']
Y_count_Week = raw_fe[['count']].rolling(24*7).mean()
Y_count_Week.fillna(method='ffill', inplace=True)
Y_count_Week.fillna(method='bfill', inplace=True)
Y_count_Week.columns = ['count_Week']
#원본과 합치기
if 'count_Day' not in raw_fe.columns:
raw_fe = pd.concat([raw_fe, Y_count_Day], axis=1)
if 'count_Week' not in raw_fe.columns:
raw_fe = pd.concat([raw_fe, Y_count_Week], axis=1)
Y_diff = raw_fe[['count']].diff()
Y_diff.fillna(method='ffill', inplace=True)
Y_diff.fillna(method='bfill', inplace=True)
Y_diff.columns = ['count_diff']
if 'count_diff' not in raw_fe.columns:
raw_fe=pd.concat([raw_fe,Y_diff],axis=1)
#날짜 변수 생성
raw_fe['temp_group'] = pd.cut(raw_fe['temp'], 10)
raw_fe['Year'] = raw_fe.datetime.dt.year
raw_fe['Quater'] = raw_fe.datetime.dt.quater
raw_fe['Quater_ver2'] = raw_fe.datetime.dt.quater+(raw_fe.Year- raw_fe.min())*4
raw_fe['Month'] =raw_fe.datetime.dt.Month
raw_fe['Day'] = raw_fe.datetime.dt.day
raw_fe['Hour'] = raw_fe.datetime.dt.hour
raw_fe['DayofWeek'] = raw_fe.datetime.dt.dayofweek
#지연값 변수 생성
raw_fe['count_lag1'] = raw_fe['count'].shift(1)
raw_fe['count_lag2'] = raw_fe['count'].shift(2)
raw_fe['count_lag1'].fillna(method='bfill', inplace=True)
raw_fe['count_lag2'].fillna(method='bfill', inplace=True)
if 'Quater' in raw_fe.columns:
if 'Quater_Dummy' not in raw_fe.columns:
raw_fe = pd.concat([raw_fe, pd.get_dummies(raw_fe['Quater], prefix='Quater_Dummy', drop_first=True)], axis=1)
del raw_fe['Quater']
return raw_fe
데이터 분리
시계열 데이터는 분리할때 시간축이 반드시 있어야 한다.
기존에 알고 있는 train_test_split, k-fold 등 분리 방법은 비시계열 데이터 분리 방법으로써 시간차원 없다
시계열데이터에 위 방법을 사용하면 시간개념이 사라지므로 1스텝 교차검사,2스텝 교차검사 분리 방법을 사용해야한다.
하얀 점들이 예측해야할 test 미래 시기이다. 시간 단위로 index가 구성되어 있으므로
하얀점들 각각이 2021-03-15 09:00, 2021-03-15 10:00, 2021-03-15 11:00 ~~~ 로 구성되어 있을것이다.
시계열데이터는 각 시기를 예측해야한다. 비시계열은 아래처럼 test를 한 곳에 뭉쳐서 성능값이 하나 나온다
만일 90%라고 나와도, 가까운 미래 정확도가 98%나오고 먼 미래 일수록 그 정확도가 떨어진다. 이 수치를 종합해서 90%라고 해도 시계열 데이터 입장에서는 신뢰할수 없는 성능 수치이다.
그래서 각 시기별로 각각 정확도를 구하고, 정확도를 구한 시기는 train으로 들어간다.
★위에 이론 내용을 토대로 실습 진행
실습은 시계열데이터지만 전통적인 데이터분리 방법을 적용했다(강의 구성이 그렇게 되어있다...)
### Data split of cross sectional
def datasplit_cs(raw, Y_colname, X_colname, test_size, random_seed=123):
X_train, X_test, Y_train, Y_test = train_test_split(raw[X_colname], raw[Y_colname], test_size=test_size, random_state=random_seed)
print('X_train:', X_train.shape, 'Y_train:', Y_train.shape)
print('X_test:', X_test.shape, 'Y_test:', Y_test.shape)
return X_train, X_test, Y_train, Y_test
### Data split of time series => 특정 날짜를 기준으로 나눈다
def datasplit_ts(raw, Y_colname, X_colname, criteria):
raw_train = raw.loc[raw.index < criteria,:]
raw_test = raw.loc[raw.index >= criteria,:]
Y_train = raw_train[Y_colname]
X_train = raw_train[X_colname]
Y_test = raw_test[Y_colname]
X_test = raw_test[X_colname]
print('Train_size:', raw_train.shape, 'Test_size:', raw_test.shape)
print('X_train:', X_train.shape, 'Y_train:', Y_train.shape)
print('X_test:', X_test.shape, 'Y_test:', Y_test.shape)
return X_train, X_test, Y_train, Y_test
Y_colname =['count']
#중복되는 count & 문자형 변수
X_remove = ['datetime', 'DateTime', 'temp_group', 'casual', 'registered']
X_colname= [col for col in raw_fe.columns if col not in Y_colname+X_remove]
X_train, X_test, Y_train, Y_test = datasplit_ts(raw_fe, Y_colname, X_colname, '2012-07-01')
'Data Diary' 카테고리의 다른 글
2021-03-17(시계열데이터 심화4_잔차진단) (0) | 2021.03.17 |
---|---|
2021-03-16(시계열데이터 심화3_시각화&모델적용&검증지표) (0) | 2021.03.16 |
2021-03-13(Opencv 복습) (0) | 2021.03.13 |
2021-03-12(시계열데이터 심화1) (0) | 2021.03.12 |
2021-03-11(제조공정 검출 + Opencv 복습) (0) | 2021.03.11 |