728x90

*본 내용은 시계열데이터 강의 내용 중 일부분을 요약한 내용입니다

 

 

이전에 올렸던 포스팅은 test 데이터를 알고 있을 경우에 FE를 진행하여 모델을 돌렸습니다. test 할 데이터에 대해서 FE를 했으므로 R^2 값이 1.0이 나왔습니다. 하지만 현실에서는 test할 데이터를 모릅니다. 미래가 어떻게 변할지는 그 누구도 모르기 때문입니다. 따라서 현실에 있을법한 test 데이터를 만들고자 합니다. 1-step 방법을 사용해서 미래 데이터 패턴을 예측하는 방법도 있지만 현 실습에서는 간단하게 진행했습니다

 

2011,2012년도 두 연도가 있는 자전거 수요 데이터에서, 현 실습에서는 2011년 데이터 패턴을 그대로 2012년도 데이터패턴에 적용했습니다. 여기에 모델을 적용한 후 스케일링 전처리 작업을 수행했습니다. 좀더 세부적인 교육 내용은 아래에 간단하게 적었습니다

 

현실성을 반영한 데이터패턴

# Test 기간의 FE데이터를 알 수 있을까? 2가지 방법소개
# 1) 과거 패턴이 반복될 것이다
# 2) 하나씩 예측하며 업데이트
'''
현재 데이터 그래프와 미래 데아터 그래프는 다르다. 이를 각각 어떻게 FE를 진행하는가?
이상적으로 가장 적합한 방법은 test 부분 영역은 아무도 모르는 영역이다-> 추정하는게 현실적으로 맞다
어떻게 추정하는가? train값으로 바로 t번재 테스트 값을 추정하고, 추정된 값을 포함한 값으로 t+1번째 값 추정 하는식 

위 방법은 복잡하므로 좀더 간단한 방법으로 실습을 진행한다.
train에서 보인 패턴이 test에도 반복될거라는 가장 하에 진행
이렇게 되면 급작스러운 패턴 변화 때문에 다소 이질감이 생길수 있다.
2011 일년치를 가져와서 덜 이질감 있도록 2012년 적용
'''

 

len(raw_fe.loc['2012-01-01':'2012-12-31', 'count_trend'])
8784

len(raw_fe.loc['2011-01-01':'2011-12-31', 'count_trend'])
8760

# 2011년도 count_trend를 2012년 count_trend에 덮어 씌울려고 시도하면 에러가 발생
길이가 24개 차이가 나기 때문이다. 현재 시간 단위는 H이므로 
24시간=> 윤달인 2월29일 데이터가 2011년도에는 없었던 것
 

 

#2월29일을 제외한 나머지 날짜를 대입
raw_fe.loc['2012-01-01':'2012-02-29', 'count_trend']=raw_fe.loc['2011-01-01':'2011-02-28', 'count_trend']
raw_fe.loc['2012-03-01':'2012-12-31', 'count_trend']=raw_fe.loc['2011-03-01':'2011-12-31', 'count_trend']

#2011-02-29데이터 만들기
step= (raw_fe['2011-03-01 00:00:00','count_trend']-raw_fe.loc['2011-02-28 23:00:00','count_trend'])/25
step_value=np.arange(raw_fe.loc['2011-02-28 23:00:00','count_trend']+step, raw_fe.loc['2011-03-01 00:00:00','count_trend'], step) 
step_value= step_value[:24]
raw_fe.loc['2012-02-29','count_trend']=step_value

raw_fe.loc['2012-02-28 22:00:00':'2012-03-01 02:00:00', 'count_trend']

 

 

raw_fe['count_trend'].plot()

 

  • 2011년도와 같은 count_trend를 가지게 되었다

 

함수로 정의하기

def feature_engineering_year_duplicated(raw, target):
    raw_fe = raw.copy()
    for col in target:
        raw_fe.loc['2012-01-01':'2012-02-28', col] = raw.loc['2011-01-01':'2011-02-28', col].values
        raw_fe.loc['2012-03-01':'2012-12-31', col] = raw.loc['2011-03-01':'2011-12-31', col].values
        step = (raw.loc['2011-03-01 00:00:00', col] - raw.loc['2011-02-28 23:00:00', col])/25
        step_value = np.arange(raw.loc['2011-02-28 23:00:00', col]+step, raw.loc['2011-03-01 00:00:00', col], step)
        step_value = step_value[:24]
        raw_fe.loc['2012-02-29', col] = step_value
    return raw_fe
target = ['count_trend', 'count_seasonal', 'count_Day', 'count_Week', 'count_diff']
raw_fe = feature_engineering_year_duplicated(raw_fe, target)

 

Lag값 새로 정의하기

# calculation of lag data from Y
X_test_fe['count_lag1'] = Y_test_fe.shift(1).values # Y_test_fe.shift(1)값으로 새로 채우기 (현재는 train lag값이 들어가 있음)
X_test_fe['count_lag1'].fillna(method='bfill', inplace=True) #nan 값 채워주기
X_test_fe['count_lag2'] = Y_test_fe.shift(2).values
X_test_fe['count_lag2'].fillna(method='bfill', inplace=True)
X_test_fe['count_lag2']


DateTime
2012-07-01 00:00:00   149.00
2012-07-01 01:00:00   149.00
2012-07-01 02:00:00   149.00
2012-07-01 03:00:00    93.00
2012-07-01 04:00:00    90.00
                       ...  
2012-12-31 19:00:00   164.00
2012-12-31 20:00:00   122.00
2012-12-31 21:00:00   119.00
2012-12-31 22:00:00    89.00
2012-12-31 23:00:00    90.00
Freq: H, Name: count_lag2, Length: 4416, dtype: float64

 

현실성을 반영한 코드 요약

### Functionalize
### duplicate previous year values to next one
def feature_engineering_year_duplicated(raw, target):
    raw_fe = raw.copy()
    for col in target:
        raw_fe.loc['2012-01-01':'2012-02-28', col] = raw.loc['2011-01-01':'2011-02-28', col].values
        raw_fe.loc['2012-03-01':'2012-12-31', col] = raw.loc['2011-03-01':'2011-12-31', col].values
        step = (raw.loc['2011-03-01 00:00:00', col] - raw.loc['2011-02-28 23:00:00', col])/25
        step_value = np.arange(raw.loc['2011-02-28 23:00:00', col]+step, raw.loc['2011-03-01 00:00:00', col], step)
        step_value = step_value[:24]
        raw_fe.loc['2012-02-29', col] = step_value
    return raw_fe
# target = ['count_trend', 'count_seasonal', 'count_Day', 'count_Week', 'count_diff']
# raw_fe = feature_engineering_year_duplicated(raw_fe, target)

### modify lagged values of X_test
def feature_engineering_lag_modified(Y_test, X_test, target):
    X_test_lm = X_test.copy()
    for col in target:
        X_test_lm[col] = Y_test.shift(1).values
        X_test_lm[col].fillna(method='bfill', inplace=True)
        X_test_lm[col] = Y_test.shift(2).values
        X_test_lm[col].fillna(method='bfill', inplace=True)
    return X_test_lm
# target = ['count_lag1', 'count_lag2']
# X_test_fe = feature_engineering_lag_modified(Y_test_fe, X_test_fe, target)

 

#현실성 반영한 모델 실행하기

# Data Loading
# location = 'https://raw.githubusercontent.com/cheonbi/DataScience/master/Data/Bike_Sharing_Demand_Full.csv'
location = './Data/BikeSharingDemand/Bike_Sharing_Demand_Full.csv'
raw_all = pd.read_csv(location)

# Feature Engineering
raw_fe = feature_engineering(raw_all)
### Reality ###
target = ['count_trend', 'count_seasonal', 'count_Day', 'count_Week', 'count_diff']
raw_feR = feature_engineering_year_duplicated(raw_fe, target)
###############

# Data Split
# Confirm of input and output
Y_colname = ['count']
X_remove = ['datetime', 'DateTime', 'temp_group', 'casual', 'registered']
X_colname = [x for x in raw_fe.columns if x not in Y_colname+X_remove]
X_train_feR, X_test_feR, Y_train_feR, Y_test_feR = datasplit_ts(raw_feR, Y_colname, X_colname, '2012-07-01')
### Reality_lag ###
target = ['count_lag1', 'count_lag2']
X_test_feR = feature_engineering_lag_modified(Y_test_feR, X_test_feR, target)
###############

# Applying Base Model
fit_reg1_feR = sm.OLS(Y_train_feR, X_train_feR).fit()
display(fit_reg1_feR.summary())
pred_tr_reg1_feR = fit_reg1_feR.predict(X_train_feR).values
pred_te_reg1_feR = fit_reg1_feR.predict(X_test_feR).values

# Evaluation
Score_reg1_feR, Resid_tr_reg1_feR, Resid_te_reg1_feR = evaluation_trte(Y_train_feR, pred_tr_reg1_feR,
                                                                   Y_test_feR, pred_te_reg1_feR, graph_on=True)
display(Score_reg1_feR)

# Error Analysis
error_analysis(Resid_tr_reg1_feR, ['Error'], X_train_feR, graph_on=True)
'''
R값이 0.9이며 유의한 변수가 25개로써 기존에 2개보다 많아졌음을 확인
Durbin-Watson도 2근방으로 다가 가면서 자기상관이 상당히 줄어들었으며
Kurtosis도 정규분포에 가까워짐

조건수는 현실 반영 전 모델과 비교 시 34,000 -> 32,000 감소를 보임
이는 독립변수가 그 전보다는 생겼다는 의미이다.
t검정을 봐도 유의한 변수들이 많이 생겼음을 확인할수있다. 조건수 수치를 보고 설명변수의 상태를 
파악할수 있다.
'''

 

 

 

 

Scaling

본 내용 설명에 앞서 condition number에 대해서 설명을 하자면 예측 정확성 향상을 위해서는 두가지 방향이 있는데

1) Train 정확도 증가+ Test 정확도 증가 

2) Train <<< Test  조건수(Condition Number) 감소

 

2번에서 train 의 정확성 보다는 test의 정확성을 더 중시한다는 의미입니다. test 정확성을 높이기 위해서는 조건수의 감소가 일어나야 합니다.  x들의 특징에서 조건수를 추출하는데 이 값이 낮을수록 2번처럼 이상적수치가 나올수 있습니다. 

 

조건수는 𝑒𝑖𝑔𝑒𝑛𝑣𝑎𝑙𝑢𝑒의 최대값,최소값의 비율을 나타냅니다. X라는 설명변수들이 서로 독립적이면 𝑒𝑖𝑔𝑒𝑛𝑣𝑎𝑙𝑢e

값들은 서로 비슷한 수치를 보입니다. 반대로 종속변수가 많을수록 두 𝑒𝑖𝑔𝑒𝑛𝑣𝑎𝑙𝑢𝑒 값은 차이가 커집니다.       

ex) 𝜆1=1, 𝜆2=100

 

따라서 조건수를 줄이기 위해서는 설명변수안에 서로 독립적이여야 Test 예측 성능을 올릴수 있습니다. 

 

*조건수를 감소하는 방법 3가지

1) 변수들의 단위차이로 숫자의 스케일들이 크게 다른 경우, 스케일링(Scaling)으로 해결 가능
2) 독립변수들 간에 상관관계가 높은 "다중공선성" 존재할 경우,
Variance Inflation Factor(VIF)나 Principal Component Analysis(PCA)를 통한 변수선별로 해결 가능
3) 독립변수들 간 의존성이 높은 변수들에 패널티를 부여하는 정규화(Resularization)로 해결 가능

 

 

Scaling

숫자가 큰 변수가 그렇지 않는 변수들보다 크게 관여될수가 있으므로 값 조정은 필수다.

 

총 4가지 방법이 있습니다

1) Standard Scaler

스케일링 후의 분포의 모양은 각기 다르다(정규분포애 근사한 형태를 띈다)

2) Min-Max Scaler(𝑋𝑖𝑡𝑚𝑖𝑛(𝑋𝑖)/𝑚𝑎𝑥(𝑋𝑖)𝑚𝑖𝑛(𝑋𝑖))

본래 분포모양을 그대로 가져가면서 범위는 동일하게 적용한다
표편이 매우 작을때 효과적, 왜일까? 
표편이 작다는 건 데이터들이 모여 있다는 뜻 -> 이상치가 없다 
이상치가 있다면 표편이 커지게 된다.
극단치 때문에 비율이 왜곡된다  
이러한 문제점을 해결하고자 Robust Scaler 사용

3) Robust Scaler(𝑋𝑖𝑡𝑄1(𝑋𝑖)/𝑄3(𝑋𝑖)𝑄1(𝑋𝑖))

25%~75% 데이터를 가지고 Min-Max Scaler 공식과 동일하게 적용

 

4) Normalizer

각 변수(Feature)를 전체 𝑛n개 모든 변수들의 크기들로 나누어서 변환(by Cartesian Coordinates)
각 변수들의 값은 원점으로부터 반지름 1만큼 떨어진 범위 내로 변환한다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90

+ Recent posts