728x90

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

 

 

정규화 방법론(Regularized Method, Penalized Method, Contrained Least Squares)

-선형회귀 계수(weight)에 대한 제약 조건을 추가함으로써 모형잉 과최적화를 맏는 방법

 

정규화 회귀분석이 왜 필요하는걸까?? 이 개념이 왜 등장 한 걸까?

아래 처럼 세가지 모델이 있다고 가정하자

이 중에서 어떤 모델이 가장 좋은 걸까? 라는 생각에서 시작이 해봅니다. 위 모델들을 아래 그래프로 설명하자면

1번 모델은 왼쪽 실선 박스에 해당하고 3번 모델은 오른쪽 회색 실선 박스에 해당됩니다. 1번은 train,test 둘다 에러가 높고 3번모델은 train에 아주아주 잘 적합이 되어서 train error는 작게 나옵니다. 그치만 정작 test error는 점점 높아집니다. train의 bias가 0에 가깝게 나왔지만 variance가 엄청 높게 나와서 test 성능이 나쁘게 나오게 된겁니다.

 

쉽게 생각하자면 시키는 일만!! 잘하는 사람입니다. 회사생활할때는 말하지 않아도, 시키지 않아도 해야하는 일들이 있는데 오른쪽 회색 박스에 있는 사람들은 훈련된 일만, 시키는 일만! 잘하고 다른건 일절 못하는 사람이라고 봐도 될것같습니다. 이럴거면 차라리 업무는 조금은 못하더라도 알아서 할줄 아는 사람이 훨씬 유능하다는 소리를 듣기 마련이죠.

 

이와 마찬가지로 train으로 훈련할때 어느정도 일반화에 가깝게 훈련을 진행해야 합니다. 따라서 train 성능이 좀 나빠지더라도 test 성능이 개선되는 편이 올바른 방향입니다. 3번 모델이 2번 모델로 만들어야 올바른 방향인데 이때 사용되는 것이 정규화 회귀분석입니다. 

 

1) Ridge Regression

빨간색 밑줄이 추가된 부분입니다. 이 부분을 최소화 하는 값을 찾는다는 의미입니다. 

아래 이미지에 나온 식이 있는데 이 전체 값이 가장 적은 숫자가 나오기 위해서는 어떻게 해야 할까요?

5000이라는 큰 값이 있어서 베타가 1만 나와도 큰 값이 더해집니다. 이 전체 값을 가장 적게 만들기 위해서는 베타가 0에 가까운 값, 예를들어 소수점 여야 합니다. 이런 식으로 베타 값에 제한을 줄수 있습니다. 그래서 책에서는 

람다 값이 커지면 정규화 정도가 커지고 가중치 베타는 커질수 없다. 작아진다 라는 얘기가 나오게 된 것입니다.

 

만일 5차식의 복잡한 모델이 있다고 가정할때, 람다값을 10000을 주게 되면 베타 값들은 거의 0으로 떨어지고 남은건 상수인 베타제로 만 남게 될것입니다. 즉 5차식이 상수가이를 언더 핏팅이라고 합니다. 

반대로 람다값이 제로에 가까운 값을 주게되면 제약이 미미하기 때문에 베타값이 다 살아나서 5차식이 그대로 사용됩니다.  여기서 정규화 정도라는 것은 "제약을 주었다",'혼란스러운 모델을 정리해 주었다' 정도의 의미가 이해하기 좋습니다

 

큰 숫자가 나오지 못하도록 제한을 한다는 의미를 다시 한번 생각해 볼 필요가 있습니다. 

어떤 회귀분석 결과의 계수값들이 말도 안되게 큰 단위로만 구성이 되어 있다고 할때 릿지를 통해서 베타(계수값)를 줄인다면 이는 스케일링 효과도 내포함을 알수 있습니다. 상식적으로 불가능한 큰 계수를 조금 더 현실성 있는 값으로 변환 해줄수 있게 되는 겁니다.

 

 

2) Lasso Regression

이번에는 절대값이 제약을 가하게 되면 0에 수렴하게됩니다. 아래 그래프를 보면서 왜 0인지 설명하겠습니다.

lasso

절대값은 제곱 형태와 달리 마름모 형태로 그래프가 생성이 됩닌다. 여기서 mse인 타원형과 만나는 지점을 보면 

w1=0입니다. 다시말해서 Y값에 영향을 주지 못하는 것들은 0으로 만들어 버리는 것이 lasso입니다.

람다를 점점 더 크게 줄 수록 제거 되는 베타 값들이 늘어 나게 됩니다.

 

 

3) Elastic Net

Lasso 식에서 Ridge의 제약 형식이 추가가 된 형태입니다. 큰 개념은 상관관계가 높은 변수의 계수는 같은 값으로 생각하겠다는 것입니다. 즉 중요하면 똑같이 중요하다 라고 하고 중요하지 않다면 똑같이 중요치 않도록 판별하겠다는 의미입니다. 저도 이 부분에 대해서는 좀더 공부가 필요해 보입니다. 완벽히 이해를 하지 못했습니다 ㅠ

 

 

앙상블 모델

오늘 앙상블 모델 강의에서 무릎을 탁치는 순간이 있었습니다. 먼저 배깅의 무릎 탁 순간을 말씀드리겠습니다

 

1. 배깅

배깅은 샘플을 여러번 뽑아서 각 모델을 학습시켜 결과를 집계(Aggregration)하는 방법입니다.여기서

무릎 탁 순간은 이 배깅이 중심극한정리의 원리와 매우 흡사하다는 점이 였습니다. 

중심극한정리는 각 샘플에서 나온 통계량 값을 다시 평균을 취하면 모집단을 대표한다는 이론입니다. 이론만 봐도 이 둘이 매우 흡사 하다는 점입니다. 

배깅 중 랜덤포레스트는 배깅의 마지막 과정인 취합 부분에서 평균을 내는것이 아니라 가장 예측 값이 잘 나온 것을 대표로 선정합니다.

 

2. 부스팅

AdaBoost

부스팅은 여러 모델들(weak learner)을 만들고, 이들을 합쳐서 하나의 stronger learner로 만듭니다.

과소적합된 부분에 가중치를 높혀서 적합한 모델로 만드는 과저인데, 과소적합된 부분을 판별하는 기준은 잔차입니다. 잔차가 크면 이를 줄이기 위해서 모델이 변하게 됩니다. 여기가 무릎 탁 순간입니다. 부스팅 원리는 잔차진단과 비슷합니다. 즉 잔차에 남아 있는 패턴들을 소거해 나간다는 큰 개념이 일치 합니다. 

 

 

*마무리 하면서

이번 포스팅에서는 실습 코드 내용보다는 이론에서 많은 걸 얻었던 내용이라서 글 위주로 적었습니다

적은 내용들 보면 간단한 것같은데 저 내용들을 깨닫기 까지의 시간이 생각보다 오래 걸렸습니다. 저처럼 같은 부분에서 막혔거나 하시는 분들에게 많은 도움이 되었으면 합니다

 

 

 

728x90
728x90

오늘 아침일찍 저감장치 장착하기 하기 위해서 가산쪽 공업사를 방문했습니다 ㅎㅎ

집에 돌아 오니까 10시라서 넉넉하게 주간에 배운 내용을 간단하게 복습했습니다

짧은 시간에 많은 걸 배우다 보니까 조금 헷갈리는 부분이 있었습니다

 

이제 3월 말이라서 그런지 불안감이 커집니다 ㅠ 30살이라서 

마치 시한부 마냥 시간이 갈수록 갑갑하게 느껴집니다

 

걱정과 생각이 많아서 남은시간에는 쉬었어요 

운동도 갔다오고~ 산책도 하고 ~

 

무튼, 다음주 부터는 시계열 알고리즘을 배웁니다 

총 63강 정도 되서 대략 2주 정도 걸릴것같습니다:D

 

그러면 다음주 월요일에 알고리즘 내용을 가지고 다시 돌아 오겠습니다

 

728x90
728x90

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

 

 

저번 포스팅에 이어서 조건수를 줄이기 위한 다중공선성(Multicollinearity) 제거를 포스팅하겠습니다.

  • 독립변수가 다른 독립변수의 조합으로 표현될 경우 다중공선성이 발생
  • 독립변수끼리 서로 상관관계가 있을경우 발생
  • 독립변수의 공분산 행렬(Covariance Matrix) 벡터공간(Vector Space)의 차원과 독립변수의 차원이 같지 않는 경우(Full Rank가 아니다)

 

다중공선성 제거 방법 2가지(VIF,PCA)

1.VIF(Variance Inflation Factor): 종속성이 높은 X들을 선택하는 방법

각 변수에 대해서 회귀분석을 실시합니다. 아래처럼 X1이라는 변수는 다른 변수의 선형결합으로 표현이 될수 있을지를 계산한게됩니다. 만일 R^2값이 크다면 X1는 다른 변수에 의해 표현이 되는 것이므로 제거 대상에 해당됩니다.

X1= aX2+bX3

 

이런 방법을 통해 모든 변수를 회귀분석을 통해 종속성이 높은 X들을 찾아냅니다.

 

위 VIF 공식에서 R^2이 클수록 VIF값도 커집니다.

 

#효과적인 X들을 VIF 방법을 통해 추출하기
from statsmodels.stats.outliers_influence import variance_inflation_factor
vif = pd.DataFrame()

#i번째 x들을 다른 x들로 회귀분석
#높을수록 선형결합으로 표현 될수 있으며 이는 종속성이 있는 변수이다.
vif['VIF_Factor']= [[variance_inflation_factor(X_train_feRS.values, i) for i in range(X_train_feRS.shape[1])]

vif['Feature'] = X_train_feRS.columns
vif.sort_values(by='VIF_Factor', ascending=True)

 

실습으로 사용방법 확인

# extract effective features using variance inflation factor
vif = pd.DataFrame()
vif['VIF_Factor'] = [variance_inflation_factor(X_train_feRS.values, i) 
                     for i in range(X_train_feRS.shape[1])]
vif['Feature'] = X_train_feRS.columns
vif.sort_values(by='VIF_Factor', ascending=True)['Feature'][:10].values


array(['count_diff', 'holiday', 'count_seasonal', 'Day', 'windspeed',
       'Quater_ver2', 'Hour', 'weather', 'Quater_Dummy_2', 'DayofWeek'],
      dtype=object)
  • 몇개의 변수를 사용했을때 성능이 가장 좋을지는 모르기 때문에 모든 경우의 수를 실행해 봐야 한다
  • 아래 결과는 순서 VIF가 낮은 순으로 정렬 후 12개 변수를 사용했을때 결과입니다. 

 

 

  • 정화도는 0.864로 기존보다 정확도가 내려갔습니다
  • windspeed를 제외한 모두가 종속변수에 영향을 주고 있으며 계수값도 이전에 비하면 현실성 있는 수치를 보입니다.
  • Kurtosis가 6.022로 정규분포로 더욱 근사한 모양을 띠고 있으며 왜도 값도 줄어 들었음을 확인할수 있습니다
  • cond.No가 1,530으로 기존 34,000보다 확연히 감소 했습니다. 조건수의 감소는 독립변수들간의 상관성 감소를 뜻합니다.

 

 

2.PCA(Principal Component Analysis)

X1~X10까지의 10개 변수를 PCA 실행하면 X1^ ~X10^ 변수에 완전히 새로운 값이 채워지게 됩니다.

이 값은 기존의 변수들 값과 어떠한 연관성이 없습니다. 따라서 이 새 값은 서로 독립적으로 생기게끔 생성되었으므로 모델에 적용하면 되지만 단점은 완전히 새 값이 나오므로 어떤 의미를 가지고 있는지에 대한 재해석이 필요합니.

강의 실습에서는 VIF만을 실습했기때문에 따로 소스는 없습니다.

 

 

 

 

 

 

 

 

*정상성프로세스 이해하기

시계열이 정상성이다 라는 뜻은 시간의 흐름에 따라 "통계적 특성(Statistical Properties)"이 변하지 않는것이다.

  • 통계적 특성(Statistical Properties): 주로 평균(Mean)과 분산(Variance)/공분산(Covariance)를 얘기하지만 이를 포함한 모든 분포적 특성을 총칭함

시간 흐름에 따라 평균,분산,자기상관(autocorr), 공분산 등 통계적 특성이 변하지 않는다라는건 아래 녹색 그래프와 같은 의미이다. 평균을 낼때는 Frequency 기준으로 계산하면 같은 값이 나온다. 이외에 빨간색 그래프는 왼쪽부터 평균이 변하는 그래프, 중간 그래프는 분산이 일정치 않은 그래프, 맨 오른쪽 그래프는 평균과 분산은 일정한데 시점별로 짤랐을때는 자기상관이 있는 경우이다.  

시계열 데이터에서 정상성이 왜 필요한 것일까?녹색 그래프 처럼 값이 일정하면 좋은 점은 무엇일까?

 

예를들어서 설명하면 한 회사의 매출액을 예측하고자 합니다. 매출액은 -값도 나올수 있으므로 그 범위는 +무한대, -무한대 입니다. 매출액이 유리천장이 있는 게 아니기 때문에 한계란 없습니다. 그러면 예측을 하는 입장에서는 이 무한대 범위에서 예측을 하면 틀릴확률이 높습니다. 그러면 Y값인 매출액을 점유율로 우회해서 표현하게되면 0~1사이의 확률값으로 표현이 되고 범위가 정해졌으므로 틀릴확률이 크게 줄어들게 됩니다. 점유율을 예측 후 이를 매출액으로 다시 변환하면 되는것이죠

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90
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
728x90

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

 

 

모델 성능 평가 후 개선 할 점이 있는지, 모델이 신뢰성이 있는 것인지를 파악하기 위해서 잔차진단을 합니다. 

총 네가지 스텝으로 구성되어있습니다.

 

1. 정상성 테스트 

 정상성이란 시간의 흐름에 따라 통계적 특성이 변하지 않는다. 즉, 시계열이 정상성이다.

 통계적 특성: 주로 평균(Mean)과 분산(Variance)/공분산(Covariance)를 얘기하지만 이를 포함한 모든 분포적 특성을 총칭합니다.

 

2. 정규분포 테스트(normality Test)

3. 자기상관 테스트(Autocorrelation Test)

4. 등분산성 테스트(Homoscedasticity)

 

잔차진단 결과 백색잡음이면 패턴을 잘 추출 했다는 의미 입니다. 

즉, 찾아낼 패턴을 다 찾은 의미인데, 그렇지 못한 경우에는 시각화 그래프가 어떠한 추세를 보인다던가 정규분포을 따르지 않는다 던가, 분산이 일정치 않고 뒤죽박죽 튄다 던가 하는 등 판별기준이 있습니다. 실습코드는 아래에 있습니다

 

백색잡음

백색잡음(White Noise)는 2가지의 속성을 만족해야 하며 하나라도 만족하지 못하면 모델이 개선의 여지가 있음을 의미합니다. 무작위한 진동 패턴(fx가 y에 최대한 근접할때 생긴다)

 

1. 잔차들은 정규분포이고, 평균 0과 일정한 분산을 가진다.

정규분포인지 아닌지를 알수 있는 방법은 시각화와 검정통계량 2가지가 있다.

*시각화: 잔차들의 값을 빈도체크하여 시각화를 할때 정규분포 모양을 따르는지 확인할수 있다.

*검정통계량 Shapiro-Wilk Test 외에 여러 방법이 존재, 유의확률을 통해 의사결정을 하여 정규분포인지를 판별(4.6.2 교육자료)

 

2. 잔차들이 시간의 흐름에 따라 상관성이 없어야 한다.

아무 잔차 2개의 시점을 뽑았을때, 이 둘의 corr은 0이여야 한다. corr=0은 서로 관련성이 없으므로 독립이라는 뜻이다.  

자기상관함수(Autocorrelation Fundtion)

한 변수 내에 다른 시간 축에 대한 데이터 상관성 분석합니다. 시간 흐름에 따라 상관성이 존재하는지를 알아 볼때 사용됩니다.

특정 변수를 lag값을 취한 뒤 corr이 있는지 계산하며 아래 그래프의 파란색 실선 범위 안에 있으면 자기상관은 없다고 판별합니다. 파란색 실선은 유의수준과 같은 역할을 합니다

 

 

  정리 차원에서 회귀분석 가정들 살펴보기(모두 만족시 패턴을 잘 뽑아낸 경우이다)

  • 종속변수와 독립변수 간에 선형서의 관계를 가져야 한다
  • 독립변수들 간에 서로 독립이어야 한다
  • 잔차의 분포가 정규분포이어야 한다
  • 잔차들이 서로 독립적으로 움직여야 한다
  • 잔차들의 분산이 서로 같아야 한다

 

#잔차와 실제 잔차 인덱스=> 시간으로 확인하든 인덱스로 확인하든 순서는 보존가능해진다=> 공부 필요
Resid_tr_reg1['Rownum'] = Resid_tr_reg1.reset_index().index

#시각화 작업

# Stationarity(Trend) Analysis: 정상성 시각화
sns.set(palette='muted', color_codes=True, font_scale=2)
sns.implot(x='RowNum', y='Error', data=Resid_tr_reg1.iloc[1:], fit_reg='True', size=5.2,
                 aspect=2, ci=99, sharey='True')
                 
# Normal Distribution Analysis_정규분포 시각화
figure, axes = plt.subplots(figsize=(12,8))
sns.displot(Resid_tr_reg1['Error'], norm_hist='True', fit=stats.norm)

## Lag Analysis
'''
x축: 잔차의 오리지널 값
y축: 1시점 이동된 시점
이 두개 시점의 correlation 값들을 표현
선형성 모양의 상관성이 있어 보인다.
2.4.2의 백색잡음이 되기 위한 조건은 어떠한 시점 두개를 뽑아도 corr이 0이여야 한다
하지만 아래 그래프를 통해, corr이 시점에 따라 변화 하고 있으므로 백색잡음이 아니다.
'''
figure, axes = plt.subplots(1,4, figsize=(12,3))
pd.plotting.lag_plot(Resid_tr_reg1['Error'], lag=1, ax=axes[0])
pd.plotting.lag_plot(Resid_tr_reg1['Error'], lag=5, ax=axes[1])
pd.plotting.lag_plot(Resid_tr_reg1['Error'], lag=10, ax=axes[2])
pd.plotting.lag_plot(Resid_tr_reg1['Error'], lag=50, ax=axes[3])

# Autocorrelation Analysis_자기상관 시각화
figure , axes = plt.subplots(2,1, figsize=(12,5))

'''
lags=100: 100 lag를 그려서 수치를 알려준다
y축: corr
0번째가 1인 이유: et와 자기자신 et의 상관성 이기 때문에 1이다.
밑면에 회색그림자:유의수준 범주, 이 값을 벗어난 만큼 자기상관이 있다고 판별하고
이 범주 안에 있다면 자기상관은 0이다.(없다고 판별) 
'''

figure = sm.graphics.tsa.plot_acf(Resid_reg1['Error'], lag =100, use_vlines=True, ax=axes[0])
figure = sm.graphics.tsa.plot_pacf(Resid_reg1['Error'], lags=100, ues__vlines=True, ax=axes[1])

#검정통계량 작업

# Error Analysis(Statistics)
# Checking Stationarity
# Null Hypothesis(대중 주장): The Time-series is non-stationalry
#adfuller: ADF 정상성테스트

stationarity = pd.Series(sm.tsa.stattools.adfuller(Resid_reg1['Error'])[0:4],
index=['Test Statistics', 'p-value', 'Used Lag', 'Used Observations'])
for key , value in sm.tsa.stattools.adfuller(Resid_tr_reg1['Error'])[4].items(): #각 p_value마다의 통계량
	Stationarity['Critial Value(%s)'%key]=value
Stationarity['Maximum Information Criteria'] = sm.tsa.stattools.adfuller(Resid_tr_reg1['Error'])[5]
Stationarity = pd.DataFrame(Stationarity, columns=['Stationarity'])


# Checking of Normality(정규분포 테스트)
# Null Hypothesis(대중 주장): The residuals are normally distributed
Normality= pd.DataFrame([stats.shapiro(Resid_tr_reg1['Error'])], index=['Normality'], columns=['Test Statistics','p-value']).T


# Checking for Autocorrelation
# Null Hypothesis: Autocorrelation is absent = 자기상관은 없다 
Autocorrelation = pd.concat([pd.DataFrame(sm.stats.diagnostic.acorr_ljungbox(Resid_tr_reg1['Error'], lags=[1,5,10,50])[0], columns=['Test Statistics']),
                             pd.DataFrame(sm.stats.diagnostic.acorr_ljungbox(Resid_tr_reg1['Error'], lags=[1,5,10,50])[1], columns=['p-value'])], axis=1).T
Autocorrelation.columns = ['Autocorr(lag1)', 'Autocorr(lag5)', 'Autocorr(lag10)', 'Autocorr(lag50)']
Autocorrelation.columns = ['Autocorr(lag1)', 'Autocorr(lag5)', 'Autocorr(lag10)', 'Autocorr(lag50)']


# Checking Heteroscedasticity(등분산성)
# Null Hypothesis: Error terms are homoscedastic(등분산이다)
# 입력form이 array로 넣어야 하므로 X_train.values
#two-sided: 크냐,작냐,같냐 구분하는 방식
# Alternative: 가설의 방향
Heteroscedasticity = pd.DataFrame([sm.stats.diagnostic.het_goldfeldquandt(Resid_tr_reg1['Error'], X_train.values, alternative='two-sided')],
                                  index=['Heteroscedasticity'], columns=['Test Statistics', 'p-value', 'Alternative']).T
Error_Analysis = pd.concat([Stationarity, Normality, Autocorrelation, Heteroscedasticity], join='outer', axis=1)

#row 순서 정렬
Error_Analysis = Error_Analysis.loc[['Test Statistics', 'p-value', 'Alternative', 'Used Lag', 'Used Observations',
                                     'Critical Value(1%)', 'Critical Value(5%)', 'Critical Value(10%)',
                                     'Maximum Information Criteria'],:]






 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90
728x90

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

 

 

 회귀모델을 적용 후 R-squared,F-분포, t검정 등의 결과가 일관성이 없을때 믿어야 할건 데이터 라는 것이다.

일관성이 없다고 효과없는 데이터를 무작정 삭제 하는게 아니라, 시각화를 통해서 종속변수에 영향을 주는 데이터인지 아닌지를 판단해야한다. 

 

모델적용

fit_reg1 = sm.OLS(Y_train, X_train).fit()
display(fit_reg1.summmary())
pred_tr_reg1 = fit_reg1.predict(X_train).values
pred_te_reg1 = fit_reg1.predict(X_test).values
'''
*R-squared
 평균치 ybar 보다 적합이 좋은지 나쁜지를 나타낸다 
 1.00은 모드예측값이 실제값과 모두 동일함을 의미한다

*F-statistic(F검정)
 유의확률이 0.00으로 유의수준보다 작으므로, 이 모델링은 효과가 있다.
 모든 계수가 효과가 있다

*t 검정
 count_diff, count_lag1를 제외하곤 모두 영향력이 없다
 F검정에는 모든 계수가 효과 있다고 했는데? 이상함을 감지 해야한다

*잔차 보기
 정규분포의 Kurtosis(첨도)는 3이다.
 현 Kurtosis는 13078.751, 일반 첨도보다 훨씬 꼬리가 두터운 형태

*정규분포의 Skew(왜도)는 0이다.
 현 Skew는 -114.255, negative 형태 (오른쪽 쏠림), 상당히 벗어난 값

*회귀분석 지표가 많은 이유는 모든 결과가 일관성 있을때 까지 시도하라는 의미
*지속적인 튜닝이 필요
*회귀분석은 값만 출력하고, 쓸지 말지는 사람이 선택한다. 따라서 합리적인 근거를 토대로
 사용여부를 결정한다. 근거의 대표적인 도구가 시각화이다.
 믿어야 할건 알고리즘이 아니라 데이터이다.
'''

 

  • 위 결과에 대한 해석은 실습의 주석처리로 되어있습니다
  • 일관성 없는 데이터에 대해서 시각화를 통해 정확한 정보를 얻어낸다
  • 이상적인 그림은 모델 적용하기 전 시각화를 통해 변수에 대한 정보를 파악하는게 맞다

 

시각화

# histogram plot
raw_fe.hist(bins=20, grid=True, figsize=(16,12)) #x를 몇개 그룹으로 나눌것이가: bins
plt.show()
'''
count와 비슷한 분포가 상관관계가 높고, 유의하다고 나올 가능성이 높다
y분포와 비슷하게 만드는 것이 예측에 도움이 될것
'''

 

# box plot_계절별 각 수요 관계 파악
raw_fe.boxplot(column='count', by='season', grid=True, figsize=(12,5))
plt.ylim(0,1000)
raw_fe.boxplot(column='registered', by='season', grid=True, figsize=(12,5))
plt.ylim(0,1000)
raw_fe.boxplot(column='casual', by='season', grid=True, figsize=(12,5))
plt.ylim(0,1000)
'''
만일 계절의 y분포 네개가 똑같다면 어떨까?
계절에 의한 count 변화는 없다는 의미이며 계절변수가 쓸모 없다는 것
계절별로 패턴이 많이 달라야 예측에 도움이 된다.
'''

 

 

 

# box plot_휴일,평일과 수요(count) 관계 파악
raw_fe.boxplot(column='count', by='holiday', grid=True, figsize=(12,5))
plt.ylim(0,1000)

raw_fe.boxplot(column='count', by='workingday', grid=True, figsize=(12,5))
plt.ylim(0,1000)

'''
휴일과 평일 비교하는 그래프에서, 평일에 수요가 훨씬 많음을 알수있다
분포가 다르고 해석되는 것에 차이가 있으므로 y분포에 도움이 될수 있다.
'''

 

 

raw_fe[raw_fe.holiday==0].boxplot(columns = 'count', by ='Hour', grid=True, figsize=(12,5))
plt.show()
raw_fe[raw_fe.holiday ==1].boxplot(columns='count', by ='Hour', grid=True, figsize=(12,5))
plt.show()
'''
두 분포간의 차이가 있으며 개별 분포를 봐도 count값 분포가 다르므로 y에 효과가 있음을 추론가능
'''

 

 

 

# scatter plot for some group
#temp를 추가해서 삼차원 그래프
raw_fe[raw_fe.workingday == 0].plot.scatter(y='count', x='Hour', c='temp', grid=True, figsize=(12,5), colormap='viridis')
plt.show()
raw_fe[raw_fe.workingday == 1].plot.scatter(y='count', x='Hour', c='temp', grid=True, figsize=(12,5), colormap='viridis')
plt.show()

'''
temp도 두 그래프의 분포가 다르므로 영향을 줄거라는 걸 추론 할수있다.
'''

 

 

# box plot example_날씨에 따른 수요 변화
raw_fe.boxplot(column='count', by='weather', grid=True, figsize=(12,5))
plt.ylim(0,1000)
raw_fe.boxplot(column='registered', by='weather', grid=True, figsize=(12,5))
plt.ylim(0,1000)
raw_fe.boxplot(column='casual', by='weather', grid=True, figsize=(12,5))
plt.ylim(0,1000)
'''
날씨에 따른 count 변화가 보인다.
'''

 

 

# box plot example_년도에 따른 수요 변화
raw_fe.boxplot(column='count', by='Year', grid=True, figsize=(12,5))
plt.show()
'''
년도에 따른 수요가 다르다는 걸 알수 있다. y에 영향을 준다
'''

 

 

# box plot example_월에 따른 수요 변화 
raw_fe.boxplot(column='count', by='Month', grid=True, figsize=(12,5))
plt.show()

 

 

 

 

#독립변수간의 상관관계를 파악하기 위한 시각화
#상관관계를 추정하는게 알고리즘의 목표
pd.plotting.scatter_matrix(raw_fe, figsize=(18,18), diagonal='kde')
plt.show()

 

  • 색깔이 짙을수록 관계성이 강하다는 의미

 

 

 

# selecting of columns from correlation tables
#y값과 x들 간의 상관관계 보기
'''
아래 값이 회귀분석 결과에 나온 계수값과 비슷한지 비교해봐야 한다
유사하지 않기 때문에 t검정이 유의하지 않다고 한것이다. 
count_lag2 회귀분석결과를 비교해도 다름을 알수있다.
'''
raw_fe.corr().iloc[:,8:11]

 

 

 

# correlation table example
raw_fe.corr().iloc[0:8,8:11].style.background_gradient().set_precision(2).set_properties(**{'font-size': '15pt'})

 

 

 

검증지표 방향

R-squared(R^2):추정된 (선형)모형이 주어진 데이터에 잘 적합된 정도, 계량경제학에서는 모델에 의해 설명되는 데이터 분산의 정도(퍼센트)

 

R-squared는 기준이 ybar이다. 이는 다른 mse,mae와 차이점이다.
-> 평균적으로 추정된 값보다 얼만큼 잘 적합이 되었는지 확인
    최소값은 마이너스 무한대이다.

 

 

 

Mean Absolute Error(MAE): 각 데이터의 단위를 보존하는 성능지표
단위보존 ? mse와 비교하면 알수있다.

 

Mean Squared Error(MSE): 가장 많이 사용되며 큰 오차에 패널티(Penalty)를 높게 부여하는 성능지표

mse는 실제값-예측값의 제곱이므로, 0보다 작은값은 더 작게, 1보다 큰 값은 더 크게 만들고 애초에 y값 자체의 스케일이 클수도, 작을수도 있다. 

 

mae는 절대값으로 이뤄져 있기 때문에 작은 값이 더 작게, 큰 값은 더 크게 계산되지 않는다
즉, mae는 y스케일을 그대로 보존할수 있다.

 

 

 

Summary

  • Squared 가 들어간 평가지표는, 이상치 하나만 있어도 오차가 제곱이 된다. 훨씬큰 오차가 반영됨
    따라서 이상치가 있다면 yes로 표기된 평가지표를 쓰기를 추천

 

 

편향, 분산 상충관계

 

*bias를 보는건 train학습이 잘되었는지(과적합인지 아닌지) 확인할때 본다
편향이 작다면 정확성가 높고 (오버핏팅)
편향이 크다면 정확성이 낮다 (언더핏팅)

 

*분산을 보는건  test 데이터에 대해서 정확성이 안정적으로 나올지 아닐지를 확인할때 본다
분산이 작다면 다른 데이터로 예측시 적은 변동 예상
분산이 크다면 다른 데이터로 예측시 많은 변동 예상

 

*이둘의 관계그래프를 보면 모델이 복잡할수록 값이 증가한다.
왜일까? 모델이 복잡할수록 train 데이터에 과적합이 되고(bias 증가), 새로운 test 데이터가 들어올때
어디로 튈지 모르게 되므로 분산값이 커진다.(variance 증가)

분산과 편향을 둘다 줄여야 오류가 작아진다

728x90
728x90

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

 

시계열 변수 추출 7종

Feature Engineering 통해  새 변수를 창출

추가된 새 변수가 무조건 종속변수에 영향을 못 줄수도 있다

예로들어 광고비 1,2,3,4(백만원 단위),  GDP 1,2,3,4(조 단위) 변수가 있을때 컴퓨터는 이 두 변수를 같은 것으로 취급한다

 

1. 빈도(Frequency): 계절성 패턴(seasonality)이 나타나기 전까지의 데이터 갯수(사람이 정함)

사람이 정하는 것은 데이터를 년단위로 짜를건지, 시간단위로 짜를 건지 등 을 말한다

예로들어 한 컬럼의 데이터가 2019,2020,2021 있을때, 사람은 연도라는 걸 알지만 컴퓨터는 지정하지 않으면 모르므로 

년도라고 지정 해줘야 한다

 

다만, 데이터를 분석할때 년도,월,일 등 분해 해서 알아봐야 한다-> 어떤 변수가 종속변수에 영향을 줄지는 해보지 않곤 모른다. 이 분해 과정에서 생기는 nan는 여러 방법으로 채울수가 있다.

nan 채우는 방법's

*빈도를 먼저 설정 시 장점

 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스텝 교차검사 분리 방법을 사용해야한다.

1-step 교차검사

하얀 점들이 예측해야할 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')
728x90
728x90

처음시작부터 기하학적 변환까지 진행했습니다

Opencv로 프로젝트를 진행해 보지 않아서 인지

완전히 머리로 들어 왔다는 느낌이 없습니다 

 

그래서 복습할때는 외우려 하기 보다는 이해 위주로 진행합니다

다음에 Opencv 써야 할 때가 온다면 실습내용과 책이 있으니까 금방 적용할수 있지 않을까 생각합니다

 

요즘 생각이 많아져서 학습에 제대로 집중이 안되네요 

내가 하고 있는게 맞는 방향인지, 제대로 컬리큘럼을 계획한건지 자신감도 떨어지고 있습니다

 

3월달 들어오면서 부터 그런것 같습니다 

하... 

 

일단 내일은 쉬고 월요일에는 시계열데이터 공부하도록 하겠습니다~

728x90

+ Recent posts