선형회귀로 시계열 예측 모델 만들 때 조심할 점

    목차
반응형

1. 데이터 선정

데이터 수도 많고 트렌드와 주기성도 매우 잘 보이는 Mauna Loa CO2 daily means 데이터를 이용하였다.

Global Monitoring Laboratory - Carbon Cycle Greenhouse Gases (noaa.gov)

 

2. 데이터 전처리

선형적으로 증가하는 트렌드도 보이고 1년 주기로 증감을 반복하는 패턴이 보인다. 트렌드와 패턴을 고려한 x인자를 만들자.

$y = c_0 + c_1 x + c_2 x^2 + c_3 x^3 + c_4 \sin(\frac{2\pi x} {T}) + c_5 \cos(\frac{2\pi x} {T}) + c_6 \sin(\frac{4\pi x} {T}) + c_7 \cos(\frac{4\pi x} {T}) \text{ where } T=1\text{ year}$

$ \sin(\frac{4\pi x} {T})$ 항과 $\cos(\frac{4\pi x} {T})$ 항은 굳이 필요한가 싶긴 하지만 일단 넣어서 진행했다.

 

def make_dataset(X, y, T):
    df = pd.DataFrame(X, columns=['X'])
    
    df['X2'] = X ** 2
    df['X3'] = X ** 3
    df['cosX'] = np.cos(2*np.pi*X/T)
    df['sinX'] = np.sin(2*np.pi*X/T)
    df['cos2X'] = np.cos(2*np.pi*2*X/T)
    df['sin2X'] = np.sin(2*np.pi*2*X/T)

    df['y'] = y

    return df

 

 

3. 일반적인 선형 회귀

일 데이터이므로 x 값을 0, 1, 2, ...로 순차적으로 증가하도록 설정해서 선형 회귀에 적합해보자.

from sklearn.linear_model import LinearRegression

df_index = make_dataset(np.arange(0, len(df)), df['데이터'], T=365.25) # 1년=365.25일
Xs = ['X', 'X2', 'X3', 'cosX', 'sinX', 'cos2X', 'sin2X']

lr = LinearRegression().fit(df_index[Xs], df_index['y'])
prd_idx = lr.predict(df_index[Xs])

트렌드는 맞는 것처럼 보이는데 패턴을 전혀 맞추지 못하는 모습을 보인다.

 

 

4. 날짜를 값으로 변경 후 선형 회귀

값으로 변경한다는 건 2024년 1월 1일을 2024.0으로, 2024년 12월 31일을 2024.99로 보는 것이다. 이렇게 하면 윤달도 자동으로 고려되며, 혹여 있을 빠진 날짜까지 고려된다.

def datetime_to_float(d):
    start_of_year = pd.Timestamp(year=d.year, month=1, day=1)
    end_of_year = pd.Timestamp(year=d.year+1, month=1, day=1) - pd.Timedelta(days=1)

    total_days = (end_of_year - start_of_year).days + 1
    elapsed_days = (d - start_of_year).days

    return d.year + elapsed_days / total_days

 

from sklearn.linear_model import LinearRegression

df['X'] = pd.to_datetime(df['년'].astype(str) + '-' + df['월'].astype(str) + '-' + df['일'].astype(str)).apply(datetime_to_float)
df_time = make_dataset(df['X'], df['데이터'], T=1) # 주기 1년

lr = LinearRegression().fit(df_time[Xs], df_time['y'])
prd = lr.predict(df_time[Xs])

잘 맞는 모습을 보인다.

 

 

5. 미래 예측

위에서 적합한 선형 회귀 모델로 미래 값을 예측해보자.

prd_times = pd.Series(pd.date_range(start='2024-3-12', end='2030-12-31', freq='D')).apply(datetime_to_float)
df_prd = make_dataset(prd_times, 0, T=1)

prd = lr.predict(df_prd[Xs])

 

 

교훈: 선형 회귀로 시계열을 적합할 때는 X를 정수 인덱스를 사용하지 말고 시간을 백분율로 바꾼 값을 쓰도록 하자.

 

6. 전체 코드

github

728x90
반응형