Date:     Updated:

카테고리:

태그: , ,


[KOGAS 빅스타 경진대회] LNG탱크 압력 예측 모델(우수상) 1편 링크


시간 파생변수 생성

앞서 1편에서 데이터 로드 및 전처리, EDA 과정을 거쳤다. 2편은 파생변수를 추가하는 과정부터 시작해보겠다.

dt 함수를 사용하면 datetime64 형식의 자료형에서 원하는 시간 변수를 추출해준다. 아래처럼 5개의 시간 파생변수를 만들어준다.

train['HOUR'] = train['TIME'].dt.hour #시간 변수 추가
test['HOUR'] = test['TIME'].dt.hour #시간 변수 추가
train['MONTH'] = train['TIME'].dt.month #월 변수 추가
test['MONTH'] = test['TIME'].dt.month #월 변수 추가
train['WEEK'] = train['TIME'].dt.weekofyear #주차 변수 추가
test['WEEK'] = test['TIME'].dt.weekofyear #주차 변수 추가
train['DAY'] = train['TIME'].dt.dayofyear #일 변수 추가
test['DAY'] = test['TIME'].dt.dayofyear #일 변수 추가
train['WEEKDAY'] = train['TIME'].dt.weekday #요일 변수 추가
test['WEEKDAY'] = test['TIME'].dt.weekday #요일 변수 추가

새로 만든 파생변수의 그래프 개형을 확인해보자.

draw_list = ["HOUR","DAY","MONTH","WEEK","WEEKDAY"]

#시간 변수를 x축에, 압력 최댓값을 y축에 두고 그린 line plot 함수
def plot_per_time(sets, draw_list):
    plt.figure(figsize=(30,10))
    idx=1
    for var in draw_list:
        groupby = sets.groupby(var).mean()
        groupby.reset_index(inplace=True)
        plt.subplot(3,2,idx)
        plt.plot(groupby[var], groupby['PIA205B-02A_MAX'])
        plt.title(var)
        idx+=1
        
plot_per_time(train, draw_list)

위 그래프를 보면 알 수 있듯이, 기온이 높아지는 시간대, 월에 target도 증가한다는 사실을 알 수 있다. 또한 요일을 놓고 보았을 때, 일,월요일에 target값이 높아지고 금요일에 가장 작아지는 것을 확인할 수 있다. 이는 요일에 따라 탱크를 작동하는 정도의 차이가 있기 때문이라고 판단하였다.


시간 변수 cos 변환

시간은 0~23이라는 정수형 타입으로 표현된다. 그런데 이렇게되면 1월 1일 23시와 1월 2일 00시가 실제로 한 시간의 차이를 가짐에도 23의 차리을 갖는 꼴이 된다. 그래서 이를 해결하고자 삼각함수로 변환하여 시간이 연속성을 갖게 할 것이다.

train['cos_day'] = np.cos(2*np.pi*(train.DAY/365))
test['cos_day'] = np.cos(2*np.pi*(test.DAY/365))
train['cos_hour'] = np.cos(2*np.pi*(train.HOUR/24))
test['cos_hour'] = np.cos(2*np.pi*(test.HOUR/24))


과거 데이터 shift

본 대회의 과제는 10, 20, 30, 40, 50분 전의 데이터를 가지고 탱크의 압력값을 예측하는 것이다. 즉, 과거의 데이터를 가지고 특정 시점의 타겟을 예측해야 하므로 모든 변수를 10분씩 당기는 과정이 필요했다. 20~60분 전의 데이터도 사용할 수 있었지만, 변수가 많아지면 overfitting의 우려가 있으므로 10분 전 변수들만 사용하기로 했다. 그러나, 탱크 압력값은 타겟에 가장 지대한 영향을 끼칠 변수이므로 10분 전 데이터뿐만 아니라 20~60분 전 데이터도 추가해줬다.

column_list = list(train.columns)
column_list.remove('TIME')
column_list_ = column_list

#TIME 변수를 제외하고 모든 변수에 대해 10분 전 LAG1 데이터를 만들어준다.
for column in column_list_:
    train['LAG1_{}'.format(column)] = train[column].shift(1)
    
column_list_.remove('PIA205B-02A_MIN')
column_list_.remove('PIA205B-02A_MAX')
remove_list_ = column_list_

#타겟 2개와 새로 만든 LAG1 변수들을 제외하고 나머지 변수들을 drop한다.
train.drop(remove_list_,axis=1,inplace=True)

#과거 압력값은 꽤 중요한 변수이기에 다른 변수와 달리 10~60분의 모든 데이터를 활용한다. 즉, LAG1~LAG6까지 만든다.
for n in range(2,7):
    for PIA in ['PIA205B-02A_MIN','PIA205B-02A_MAX']:
        train['LAG{}_{}'.format(n, PIA)] = train[PIA].shift(n)

아래 발표자료 캡처본을 참고하면 shift하는 작업에 대한 이해를 도울 수 있을 것이다.


탱크 압력값 관련 파생변수 생성

변수들을 shift한 것을 바탕으로 이번에는 탱크 압력값을 활용한 파생변수들을 만들 것이다.

#LAG의 변화량 역시도 중요한 요소로 작용할 것이기에 LAG1과 LAG2의 차를 변수로 만든다.
#lAG1과 LAG2의 차
train['MIN_DIFF_12'] = train['LAG1_PIA205B-02A_MIN']-train['LAG2_PIA205B-02A_MIN']
train['MAX_DIFF_12'] = train['LAG1_PIA205B-02A_MAX']-train['LAG2_PIA205B-02A_MAX']


#lAG1과 LAG2의 차의 제곱
train['MIN_DIFF_12SQ'] = train['MIN_DIFF_12']**2
train['MAX_DIFF_12SQ'] = train['MAX_DIFF_12']**2


#lAG1과 LAG2의 곱
train['MIN_DIFF_12X'] = train['LAG1_PIA205B-02A_MIN']*train['LAG2_PIA205B-02A_MIN']
train['MAX_DIFF_12X'] = train['LAG1_PIA205B-02A_MAX']*train['LAG2_PIA205B-02A_MAX']

#LAG1 MIN과 LAG1 MAX의 차
train['DIFF_MAXMIN'] = train['LAG1_PIA205B-02A_MAX'] - train['LAG1_PIA205B-02A_MIN']
#shift로 인해 변수가 NaN값으로 유실된 row는 버려준다.
train_ = train[6:]

#타겟은 y에, 변수는 x에 넣어준다.
y = train_.iloc[:,1:3]
x = train_.iloc[:,3:]


test set에도 동일한 작업 수행

이제 test set도 train set과 동일한 작업을 해줄 것이다. 코드 원리는 상기한 것과 같다.

column_list = list(test.columns)
column_list.remove('TIME')
column_list_ = column_list

for column in column_list_:
    test = test.rename(columns={column:'LAG1_{}'.format(column)})

for n in range(1,6):
    for PIA in ['LAG1_PIA205B-02A_MIN','LAG1_PIA205B-02A_MAX']:
        test['LAG{}_{}'.format(n+1, PIA[5:])] = test[PIA].shift(n)


#lAG1과 LAG2의 차
test['MIN_DIFF_12'] = test['LAG1_PIA205B-02A_MIN']-test['LAG2_PIA205B-02A_MIN']
test['MAX_DIFF_12'] = test['LAG1_PIA205B-02A_MAX']-test['LAG2_PIA205B-02A_MAX']

#lAG1과 LAG2의 차의 제곱
test['MIN_DIFF_12SQ'] = test['MIN_DIFF_12']**2
test['MAX_DIFF_12SQ'] = test['MAX_DIFF_12']**2


#lAG1과 LAG2의 곱
test['MIN_DIFF_12X'] = test['LAG1_PIA205B-02A_MIN']*test['LAG2_PIA205B-02A_MIN']
test['MAX_DIFF_12X'] = test['LAG1_PIA205B-02A_MAX']*test['LAG2_PIA205B-02A_MAX']

#LAG1 MIN과 LAG1 MAX의 차
test['DIFF_MAXMIN'] = test['LAG1_PIA205B-02A_MAX'] - test['LAG1_PIA205B-02A_MIN']

test_ = test[5::6]
test_.drop('TIME',axis=1,inplace=True)
test_.reset_index(drop=True,inplace=True)
test_with_sub = pd.concat((submission,test_), axis=1)
test_data = test_with_sub.iloc[:,3:]

#columns 순서 train data와 동일하게 맞추기
test_data = test_data.reindex(columns=x.columns)


다음 편에서는 모델링 과정을 이어나가보겠다.

[KOGAS 빅스타 경진대회] LNG탱크 압력 예측 모델(우수상) 3편 링크