지연값 추출
(count_lag1, count_lag2)
시간의 흐름이 존재하고 있는 데이터에서, 특정한 데이터는 현재 종속변수 Y에 영향을 주는 것이 아닌, 미래의 시간의 종속변수 Y에 영향을 주는 경우가 존재한다.
예를 들어, 투자지원금을 받았다고, 받은 날부터 실적이 오르는 것보다는, 그 이후에 투자지원금을 효율적으로 쓰고, 시간이 어느정도 지난 후에 실적이 나온다는 것을 생각하면 이해하기 쉽다.
이 특성을 데이터 분석에 반영하기 위해서, Series.shift( )를 사용하면 된다. 인자로 입력되는 숫자만큼 데이터가 뒤로 밀리게 된다.
당연히, 뒤로 밀린 개수만큼의 데이터가 NaN값으로 채워지게 되고 이것은 이전에 결측치를 채웠던 방식처럼 pd.fillna( )의 method = 'bfill' , 'ffill'을 이용한다.
raw_all['count_lag1'] = raw_all['count'].shift(1)
raw_all['count_lag2'] = raw_all['count'].shift(2)
raw_all['count_lag1'].fillna(method='bfill', inplace=True)
raw_all['count_lag2'].fillna(method='bfill', inplace=True)
raw_all
카테고리형 변수 원-핫 인코딩(One-Hot Encoding)
(Quater_Dummy)
이전 포스팅에서, 각 분기를 datetime 객체에서 추출했고, 그것을 별도의 특성으로 만들어 DataFrame에 추가했다.
하지만, 이렇게 데이터를 전처리 했을 때 문제가 발생한다. 일단 여러 알고리즘이 카테고리형 변수를 포함하는 DataFrame을 해석하지 못하는 경우가 많고, 우리가 생각하지 못했던 부분에서 Overfitting이 발생하게 될 수도 있다.
예를 들어,
봄 : 1, 여름 : 2, 가을 : 3, 겨울 : 4 로 지정을 한 카테고리 형식을 데이터에 집어넣어 분석을 한다면 사람은 1, 2, 3, 4를 숫자로 인식하는 것이 아니라 카테고리의 이름으로 인식을 한다. 하지만 컴퓨터에서는 봄이 네 번 있으면 겨울이 되는 즉, '봄 * 4 = 여름'이라는 공식이 성립하는 숫자로 인식을 한다.
이렇게 알고리즘과 사람이 인식하는 것의 차이로 인해서, 예측 성능이 떨어지는 경우가 있다. 이런 문제를 해결하기 위해서는 원 - 핫 인코딩이라는 기법을 사용한다.
원 - 핫 인코딩 : 카테고리형 데이터의 각 범주를 하나의 열로 만들어서, 해당 데이터가 해당하는 것에만 1을 표시하고, 나머지 범주에 대한 열에는 0을 표시하는 기법을 의미한다.
원-핫 인코딩을 판다스를 통해서 구현하기 위해서는 pd.get_dummies( ) 함수가 필요하다.
pd.get_dummies(raw_all['Quater'])
위와 같이 하나의 열에 포함되어있던 데이터가 카테고리의 개수만큼 열이 늘어나는 것을 확인할 수 있다.
if 'Quater' in raw_all.columns:
raw_all = pd.concat([raw_all, pd.get_dummies(raw_all['Quater'], prefix='Quater_Dummy', drop_first=True)
], axis=1)
del raw_all['Quater']
raw_all
pd.get_dummies( )에 prefix, drop_first라는 옵션을 설정을 해주었다.
prefix : string형태로 입력을 해서, 새롭게 만들어지는 열의 이름에 대부분 해당 값이 저장되는데, 그 앞에 공통적으로 입력한 string이 붙여서 열이 생성된다.
drop_first : Overfitting을 줄여주기 위해서 카테고리의 개수에서 가장 첫번째는 나머지가 0이라면 해당 열을 나타내는 것이라고 볼 수 있으므로 굳이 열을 하나 쓰지 않고도 모든 경우를 표현할 수 있다.
함수화
지금까지 수행한 모든 전처리 과정을 하나의 함수로 제작해서, 사용하는 입장에서, 데이터 전처리를 한번에 할 수 있도록 만들어 준다.
def non_feature_engineering(raw):
raw_nfe = raw.copy()
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)
raw_nfe = raw_nfe.asfreq('H', method = 'ffill')
return raw_nfe
non_feature_enginnering( )은 별도로 데이터 내부의 작업을 하지 않고 단지 Datetime을 인덱스로 변환하며 시간의 단위를 H로 지정해줌으로써 혹시 있을 결측치를 채워주는 역할까지 한다.
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)
raw_fe = raw_fe.asfreq('H', method = 'ffill')
# 여기까지는 위의 non_feature_engineering과 동일하다.
result = sm.tsa.seasonal_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:
if 'count_seasonal' not in raw_fe.columns:
raw_fe = pd.concat([raw_fe, Y_trend, Y_seasonal], axis = 1)
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.quarter
raw_fe['Quater_ver2'] = raw_fe['Quater'] + (raw_fe.Year - raw_fe.Year.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 ['_'.join(col.split('_')[:2]) for col 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
feature_engineering( )은 지금까지 했던 모든 데이터 전처리 과정을 하나의 함수에 정리한 것이다.
참고 자료 : 시계열 데이터 분석 A - Z
'딥러닝 > 시계열' 카테고리의 다른 글
시계열 분석 실습 코드 - 5 (시각화, 상관도) (0) | 2021.03.04 |
---|---|
시계열 분석 실습 코드 - 4 (0) | 2021.02.19 |
시계열 데이터 분석 코드 - 2 (0) | 2021.02.17 |
시계열 데이터 분석 실습 코드 - 1 (0) | 2021.02.16 |
시계열 데이터 분리, 분석 성능 확인 (검증지표, 잔차진단) (0) | 2021.02.16 |
최근댓글