본문 바로가기

인공지능/딥러닝

[시계열분석] 주식데이터 주가예측 - ARIMA 모델 (잔차검증, 훈련 및 예측, 시각화)

~ 목차 ~

 

잔차 🐥

 


 * 잔차 : 실제값과 예측값과의 차이
 * 잔차 검정 : 정상성, 정규성 등을 만족하는지 확인하는 검정
 * 검정하는 함수 : summary(), plot_dignstics()

 

 

 

Best Model을 이용해서 잔차 확인

 

잔차 검정 - summary()


model.summary()

 

summary()

 

(해석)
P>|z| : p-value > 0.05 = 유의미하다 = 정상성을 띈다
Heteroskedasticity (H) : 이 값이 클수록 정규분포를 띄고 있다. (수치 약간 낮은 편)

 

 

잔차 검정 - plot_diagnostics()


model.plot_diagnostics(figsize=(16, 8))
plt.show()

 

plot_diagnostics함수

 

(해석)


Normal Q-Q( 잔차의 정규성 플롯 ) : 빨간선이 데이터와 일치하면 정규분포를 띄고 있다.
                                                          (이 그래프는 양 끝에가 벗어나 있으므로 정규분포 X)

 


 

ARIMA 모델 훈련 및 테스트하기

 

 

시계열 데이터 훈련 및 테스트 데이터 분리 🐥

 

 
 - 훈련 및 테스트 데이터 = 9 : 1로 분리
 - 시계열 데이터는 train_test_split() 함수를 사용하지 않습니다.
    → 연속성을 띄는 데이터의 특성상, 데이터를 앞/뒤의 비율로 분리합니다.

 

 

훈련 및 테스트 데이터 = 9 : 1로 분리


split_ratio = 0.9
split_index = int(len(data) * split_ratio)

train_data = data.iloc[:split_index] 
test_data = data.iloc[split_index:]

train_data.shape, test_data.shape

 

((2265,), (252,))

 

 

auto_arima : 모델 설정 및 Best Model 추출

 

  * auto_arima훈련과 동시에 베스트 모델을 생성해 줍니다.


model_fit = pm.auto_arima(
    y = train_data,
    ### ndiffs 방법으로 찾은 결정 차수 사용하는것이 좋음
    d = n_diffs,
    start_p=0, max_p=3,
    start_q=0, max_q=3,
    m=1, seasonal=False,
    stepwise=True,
    trace=True
)

 

auto_arima함수 실행

 

 


model_fit.summary()

 

summary

 

 


 

Best Model을 이용하여 예측(Predict)하기

 

 

시계열 예측하기(forecast) 🐥

 


 * 시계열에서 예측 용어 : forecast 라고 칭합니다.
 * 예측 결과 : 예측데이터상한가(상한 바운드), 하한가(하한 바운드)
 * 결과 시각화 : 기존값과 예측값이 연결된 시각화
 * 수행방법 : forecast 함수 생성 후 predict 수행
                   : 예측결과 반환

 

 

향후 예측 함수

 - model : Best Model
 - n : 예측하려는 향후 기간 (디폴트로 1을 지정했음)

 

 - n_periods : 예측기간 (day일단위)
 - return_conf_int : 신뢰구간 반환여부
 - fc : 예측결과(y_pred)
 - conf_int : 신뢰구간

 - asarray(): 배열로 바꾸는 함수 / tolist(): 리스트로 바꾸는 함수

 


def forecast_n_step(model, n=1):
    ### 예측하기
    fcconf_int = model.predict(n_periods=n, return_conf_int=True)
    
    # print(fc, conf_int)
    ### 반환값은 리스트형태로 변환해서 전달
    return (
        fc.tolist()[0:n],
        np.asarray(conf_int).tolist()[0:n]
    )

 

forecast 함수 생성하기


import pandas as pd

def forecast(len, model, index, data=None) :
    ### 결과값을 담아서 반환할 변수
    y_pred = []
    pred_upper = []
    pred_lower = []

    ###데이터(data)가 있는 경우
    if data is not None :
        for new_data in data :
            ### 예측하기 : 반복수행을 위해 함수로 생성
            fc, conf = forecast_n_step(model)

            ### 예측결과 리스트에 담기
            y_pred.append(fc[0])

            ### 상한가
            pred_upper.append(conf[0][1])

            ### 하한가
            pred_lower.append(conf[0][0])

            ### 시계열에서는 데이터별로 Model을 갱신함
            model.update(new_data)
            
    
    ###데이터(data)가 없는 경우
    else 
        for in range(len):
            fc, conf = forecast_n_step(model)
            
            ### 예측결과 리스트에 담기
            y_pred.append(fc[0])

            ### 상한가
            pred_upper.append(conf[0][1])

            ### 하한가
            pred_lower.append(conf[0][0])

            ### 시계열에서는 데이터별로 Model을 갱신함
            model.update(fc[0])
        

    ### 결과값에 대해서는 시리즈 타입으로
    return pd.Series(y_pred, index=index), pred_upper, pred_lower

 

 

forecast 함수 호출하기

함수 호출하기
 - fc : 예측결과
 - upper : 상한가
 - lower : 하한가

 


### model_fit(베스트 모델) / test_data.index (날짜 데이터)
fc, upper, lower = forecast(len(test_data), model_fit, test_data.index, data=test_data)

fc, upper, lower

 

 

더보기

(Date
 2021-10-29     96.433256
 2021-11-01    146.727907
 2021-11-02    145.113369
 2021-11-03    145.121421
 2021-11-04    147.463206
                  ...    
 2022-10-24    101.464312
 2022-10-25    102.958099
 2022-10-26    104.894401
 2022-10-27     95.389597
 2022-10-28     92.424132
 Length: 252, dtype: float64,
 [98.85951738604514,
  149.88611770581687,
  148.2726676426495,
  148.28019180318753,
  150.6017662415589,
  151.38984642459943,
  152.78340487937427,
  152.3548547636148,
  152.62304610556015,
  149.85085927774028,
  149.93932365840647,
  152.73596394598113,
  152.69024603875164,
  152.24253442847936,
  152.301423067861,
  153.82400826446695,
  153.25966524767358,
  150.35866608742606,
  149.9359790285766,
  149.94798926821701,
  146.18180502482008,
  149.06324542394535,
  146.01981213926393,
  144.64612314064308,
  147.00860745749978,
  145.78401348382775,
  146.91850164909178,
  151.11709768634515,
  151.9977285476294,
  151.31689000061846,
  151.8723456784901,
  150.02822455870975,
  148.20131231335756,
  150.4680242911127,
  148.25338974203163,
  145.99246757560502,
  145.656771596219,
  147.33128220525225,
  150.11351342742003,
  150.3902552519584,
  151.2248463547664,
  149.78026802501938,
  149.64920899089864,
  149.29160432204966,
  147.91291616679135,
  148.26340000601732,
  147.6811280586026,
  141.15301548436008,
  140.6040353138782,
  140.36119518062947,
  141.63962190022798,
  143.27593083335984,
  144.776413894338,
  142.53122443422316,
  142.8671947467239,
  139.7702715233164,
  138.74088662464933,
  136.91590127094588,
  133.3510216985728,
  133.56060731602795,
  130.1478103961262,
  132.22853418556116,
  132.50483922237814,
  136.21764029233765,
  139.00872002980512,
  140.96129813630498,
  150.9480493355987,
  146.40865069276424,
  145.9483799566807,
  142.62330037182684,
  142.21040802962725,
  144.76915778548175,
  141.97798278518232,
  137.5490650845943,
  138.4203208697191,
  139.73095804225133,
  140.68342292786008,
  135.88061611840163,
  133.64955839261572,
  132.78067664376914,
  130.8780778196705,
  135.6940372744686,
  137.86643675895442,
  138.11107930934799,
  137.51628599978142,
  137.9588170195678,
  137.64905764910085,
  135.4625051316426,
  129.96922435002898,
  130.38426794793057,
  136.96918061226867,
  136.14501767978928,
  133.7622135800662,
  130.2022793932192,
  132.72001636973351,
  136.95629071343873,
  137.88305691907462,
  140.01955999683753,
  139.8446915796581,
  143.37647781613526,
  142.01391508642254,
  144.36216713319268,
  144.9737096566958,
  145.14552541303857,
  146.5640929456717,
  145.97073641023277,
  143.0744645033437,
  143.88400364885862,
  146.89267973801768,
  144.5201449931969,
  140.5637658253979,
  139.75542028453617,
  137.43518173546565,
  133.21425381310388,
  131.67699046687272,
  133.5197263077047,
  130.73857756965003,
  131.13201607889164,
  133.81994230496636,
  131.6666142759096,
  128.31895284311378,
  123.10245519401201,
  126.30880377573217,
  123.15542499016841,
  118.33420284172045,
  122.5674903056691,
  118.59159592104594,
  120.20932057163654,
  121.58246611555386,
  125.6399902947269,
  120.53124874099005,
  118.79246086128026,
  116.668173438869,
  117.70700019273197,
  117.45903620048482,
  116.44142657506148,
  119.73399276055777,
  118.28736993175514,
  119.85906845903561,
  116.06585391988912,
  113.97990815066743,
  112.78725094242543,
  114.81582119047776,
  109.6799668841549,
  108.95133212966361,
  111.65954545505289,
  115.9221783958202,
  117.46891081930384,
  117.44005634268021,
  120.95817097512302,
  118.16397313871835,
  120.1003059854188,
  120.73249093511764,
  120.5083165953807,
  118.44233110567755,
  114.86002546103927,
  110.41370265220564,
  110.43316478589095,
  113.6710249649667,
  110.22962637732927,
  111.03168721481741,
  115.30082597506708,
  115.44876011325081,
  115.9923360605597,
  121.6740404309968,
  120.23294609196063,
  116.00153332561922,
  115.61670230763525,
  112.89173133463628,
  112.38652083777234,
  117.09210958253887,
  118.6398459504796,
  122.48156865464112,
  123.63996409250872,
  120.02277310172188,
  118.2446093152666,
  115.68637191949705,
  114.79329660244126,
  116.11500822779074,
  113.44469402779934,
  117.71032630208222,
  118.26497126327232,
  118.3135958186278,
  112.13664068824158,
  111.39211243657014,
  109.09379768111027,
  116.44361339918838,
  118.29178971606287,
  119.7727663555229,
  119.11856387319028,
  119.14533694926237,
  122.15601167465837,
  122.3023120662543,
  121.65131452543146,
  121.54349166492906,
  120.94654594869391,
  123.88994177479853,
  123.38002849473746,
  125.83463654333252,
  126.42367790808983,
  125.8616223677806,
  123.87769649053547,
  124.15663432172781,
  121.73883562179829,
  118.50503092046549,
  118.18270068916907,
  118.11428260346031,
  120.96687687648286,
  115.13000065333698,
  113.55638686800202,
  113.47267998570784,
  112.51431612793075,
  113.93073873934054,
  112.21116602060009,
  110.88376112423268,
  113.75884920799321,
  112.97416026296672,
  114.9975031928157,
  115.40594006144529,
  108.97993029655473,
  109.11689754785728,
  107.52844636426005,
  106.94139229483342,
  107.32678748402881,
  105.31758401209683,
  103.4800170931295,
  103.93338805705007,
  102.69212665445306,
  102.1851807876706,
  101.56948981559646,
  103.99275448682953,
  101.7427964681425,
  99.52672873476168,
  102.59319559482692,
  105.76041115198541,
  105.69728989654605,
  105.63016293769043,
  103.14191593884141,
  102.08465853081564,
  101.53176319323708,
  101.6728404476556,
  103.09216233208382,
  100.74650252670982,
  103.93932313809015,
  104.94152992571709,
  103.69000789192245,
  103.95471928444113,
  104.85530593383417,
  106.34881928730078,
  108.28545442777941,
  98.80053924787627,
  95.83630463788589],
 [94.00699438173665,
  143.56969646530794,
  141.95407101657204,
  141.96264922517767,
  144.32464477303438,
  145.07541132893155,
  146.4649780749609,
  146.04090692678506,
  146.31480598359036,
  143.53624145790022,
  143.6246053582737,
  146.41970054484287,
  146.37518843163133,
  145.92866249187972,
  145.98877792291304,
  147.5114706509048,
  146.94803574283208,
  144.0440109452062,
  143.62240548432717,
  143.6356516175576,
  139.8630782693517,
  142.7411190584796,
  139.6932734599871,
  138.3195433846947,
  140.68062451076835,
  139.45668477064217,
  140.59107256496858,
  144.78349874925956,
  145.66461278563818,
  144.9850841851004,
  145.5416888435106,
  143.69695988434003,
  141.8693465981458,
  144.13491041724458,
  141.9186815133104,
  139.65628045025016,
  139.32193680647472,
  140.99631812871945,
  143.77615950321749,
  144.05400633359793,
  144.88937616184407,
  143.4447679836722,
  143.3151114074594,
  142.95866422993132,
  141.5798273629268,
  141.93190007080557,
  141.35063910213245,
  134.80170826798394,
  134.25365963410715,
  134.0119656996788,
  135.29083831012164,
  136.92710361009085,
  138.42780150572824,
  136.1810377014555,
  136.51750651925818,
  133.4171421315886,
  132.38807349275177,
  130.5627540961426,
  126.99291350464996,
  127.20349890045703,
  123.7858015342221,
  125.86496223907231,
  126.14371878870199,
  129.8496780129342,
  132.63837655534357,
  134.59034453717763,
  144.52950686505758,
  139.9789094493787,
  139.51602988525218,
  136.189778200797,
  135.77867770100735,
  138.33603111247766,
  135.54475899308974,
  131.10407836259236,
  131.97597278404533,
  133.28706518316503,
  134.24049897225615,
  129.42671351110062,
  127.19475110211371,
  126.32634716020463,
  124.42345429678672,
  129.22919885052374,
  131.40087588356795,
  131.6466818066055,
  131.05293635800012,
  131.49656751723597,
  131.18798177583167,
  129.000288610206,
  123.49308610747696,
  123.90922407283851,
  130.47496637865274,
  129.65143366928075,
  127.26726703160857,
  123.70210364657787,
  126.21776904407938,
  130.44733415871738,
  131.37471442183724,
  133.51053264883956,
  133.33684297038837,
  136.86374134842157,
  135.50124713701942,
  137.84781349057604,
  138.4605219471216,
  138.63357231365808,
  140.05215865075013,
  139.46037791887667,
  136.56096703999546,
  137.37128286759824,
  140.37723624232203,
  138.00298457562414,
  134.0403752871912,
  133.23283285232645,
  130.91114383040505,
  126.68294831874944,
  125.14547345946994,
  126.98748410713355,
  124.20426215387288,
  124.59884310726243,
  127.28489633116924,
  125.1302690618658,
  121.77864497007704,
  116.55023724679651,
  119.75261217738677,
  116.59500245833728,
  111.76472155588895,
  115.99123701923627,
  112.00878462627303,
  113.62572732889444,
  114.99751199212132,
  119.04965930462963,
  113.92851572609926,
  112.18992317299617,
  110.064317255652,
  111.10377877882657,
  110.85737038526194,
  109.84005758000663,
  113.12901985911115,
  111.6824864530893,
  113.25411677660368,
  109.45452595801254,
  107.36816332024506,
  106.17589890321625,
  108.20356631931371,
  103.05544469045186,
  102.32792280318621,
  105.03421193667648,
  109.28983922708653,
  110.83676681806092,
  110.80912411997778,
  114.32268736586799,
  111.52555318025429,
  113.46117078356687,
  114.09671429573747,
  113.87155437502233,
  111.80450047154154,
  108.21728669830486,
  103.7632608887919,
  103.78463157781617,
  107.01834811448614,
  103.5722380722042,
  104.37507372853473,
  108.63728745332921,
  108.7880607447052,
  109.33141720102645,
  114.99975567529702,
  113.55835376843092,
  109.31971085260258,
  108.93656245831087,
  106.20928631279126,
  105.70517787080502,
  110.40214548936247,
  111.95008051210023,
  115.78618997372438,
  116.94555281277285,
  113.32316103104957,
  111.54496663794073,
  108.98485581764888,
  108.09272032887198,
  109.41498286321,
  106.74231072416536,
  111.00034679370975,
  111.5564160800235,
  111.60630184863298,
  105.41242994059436,
  104.66865012274845,
  102.36866337867544,
  109.6944465390189,
  111.54236136532963,
  113.02571019768989,
  112.37151955483895,
  112.39789215193335,
  115.40574672773948,
  115.55366809434656,
  114.9036915930047,
  114.79711902426479,
  114.20121285400012,
  117.14184352283223,
  116.63300568395023,
  119.08587022269282,
  119.67611486803797,
  119.11518071736845,
  117.13052037215988,
  117.4106533458735,
  114.99111784032296,
  111.75402010793215,
  111.43288908032686,
  111.3657041065735,
  114.21585388111076,
  108.36377555004397,
  106.79063074972646,
  106.70804862491143,
  105.75124696800808,
  107.16699811383671,
  105.44796435625382,
  104.12123021844249,
  106.99329819540138,
  106.20963599856096,
  108.23201863921976,
  108.64175406462915,
  102.19855364349513,
  102.33712395453846,
  100.74773509144549,
  100.1637587335738,
  100.5485629959665,
  98.5387020711062,
  96.70085494661629,
  97.15543633410935,
  95.91474067426711,
  95.40878591054543,
  94.79414113676631,
  97.21578179440176,
  94.96447568038172,
  92.74768260795322,
  95.81140175345341,
  98.97549237237729,
  98.91363489448345,
  98.84773949461321,
  96.3578245455941,
  95.30153842017982,
  94.74953558302087,
  94.89179686794259,
  96.31171576330992,
  93.96448231512959,
  97.15354401126038,
  98.15685778023378,
  96.90628191516043,
  97.17180962555267,
  98.07331768151398,
  99.5673784503432,
  101.50334710359785,
  91.97865481056202,
  89.01196022731773])

 

상한가와 하한가의 리스트 타입 데이터를 
   - 날짜를 인덱스로하는 시리즈 타입으로 변환하기

 

   - 추후 시각화시 결과값의 인덱스와 매핑하여 그리기 위해서...


lower_series = pd.Series(lower, index=test_data.index)
upper_series = pd.Series(upper, index=test_data.index)

lower_series, upper_series

 

 

 
 

 

전체 시각화

 

훈련데이터, 테스트데이터 시각화


plt.figure(figsize=(20, 6))
plt.title("시계열 분석 결과 시각화")

### 훈련데이터 그리기 (90%)
plt.plot(train_data, label="train_data")

### 테스트데이터 그리기 (10%)
plt.plot(test_data, label="test_data(예측 전 실제값)", c="b")

### 테스트데이터로 예측한 결과 그리기
plt.plot(fc, label="예측결과", c="r")

### 상한가(상한 바운드), 하한가(하한 바운드) 그리기 
# alpha=.5 : 투명도 (숫자가 낮을수록 투명해짐)
plt.fill_between(lower_series.index, lower_series, upper_series, alpha=.9, color="b")



plt.legend()
plt.show()

 

훈련, 테스트 훈련 결과

 


plt.figure(figsize=(20, 6))
plt.title("시계열 분석 결과 시각화")

### 훈련데이터 그리기 (90%)
# plt.plot(train_data, label="train_data")

### 테스트데이터 그리기 (10%)
plt.plot(test_data, label="test_data(예측 전 실제값)", c="b")

### 테스트데이터로 예측한 결과 그리기
plt.plot(fc, label="예측결과", c="r")

### 상한가(상한 바운드), 하한가(하한 바운드) 그리기 
# alpha=.5 : 투명도 (숫자가 낮을수록 투명해짐)
plt.fill_between(lower_series.index, lower_series, upper_series, alpha=.5, color="c")



plt.legend()
plt.show()

 

테스트데이터만 확대

 

 


 

 

모델 성능평가

 

라이브러리


from sklearn.metrics import mean_absolute_errormean_squared_error
import math

 

 

평균제곱오차(MSE)

 - np.exp( x ) : 입력 값 x에 대한 지수 함수를 계산하여 반환, e^x

 


mse = mean_squared_error(np.exp(test_data), np.exp(fc))
mse

 

4.535004495593973e+128

 

 

평균절대오차(MAE)


mae = mean_absolute_error(np.exp(test_data), np.exp(fc))
mae

 

4.297931556627558e+63

 

 

RMSE(Root Mean Squared Error)

 - 예측값과 실제값 간의 거리를 나타내는 지표
 - 값이 작을수록 모델의 성능이 좋다고 해석

 


rmse = math.sqrt(mean_squared_error(np.exp(test_data), np.exp(fc)))
rmse

 

2.129554999429217e+64

 

 

MAPE(Mean Absolute Percentage Error)

 - 예측값과 실제값 간의 백분율 오차 평균

 


mape = np.mean(np.abs(np.exp(fc) - np.exp(test_data)) / np.abs(np.exp(test_data)))
mape * 100

 

11890.702675333598

 


 

 

1년 후 예측하기 (한국 증권거래소) 🐥

 


 * 한국 증권거래소(KRX)의 주식거래일을 기준으로 → 1년 후 예측하기
 * 사용 라이브러리
     - 한국증권거래소(KRX)의 주식거래일자에 대한 데이터 수집을 위한 라이브러리
     - 라이브러리 설치 : pip install exchange_calendars 

 

 

 

한국 증권거래소(KRX)의 주식거래일을 기준으로 → 1년 후 예측하기

 

라이브러리


import exchange_calendars as ecals

 

 

주식 거래일자 수집하기


### 원본 인덱스의 마지막 인덱스 일자 이후부터 1년치에 대한 거래일자 수집
# 거래 시작일
start = "2022-11-01"
# 거래 종료일
end = "2023-10-31"

### 한국증권거래소(KRX) code값 : XKRX
k = ecals.get_calendar("XKRX")
k

 

 

시작 및 종료 기간 동안의 거래일 정보 가지고 오기


df = pd.DataFrame(k.schedule.loc[start : end])
df

 

거래일 정보 가져오기

 

 

날짜 형태 변환 - open 컬럼을 사용

 - open컬럼을 사용하기 위해 날짜 정보를 리스트에 추가하기

 


data_list = []
for in df["open"]:
    data_list.append(i.strftime("%Y-%m-%d"))
    # print(i.strftime("%Y-%m-%d"))

### DatetimeIndex 형태로 변환하기
date_index = pd.DatetimeIndex(data_list)
date_index

 

날짜 형태 변환하기

 

1년 후 주가 예측하기


fc2, upper2, lower2 = forecast(len(date_index), model_fit, date_index)
fc2

 

2022-11-01     96.546121
2022-11-02     96.615374
2022-11-03     96.617080
2022-11-04     96.662884
2022-11-07     96.680745
                 ...    
2023-10-25    103.528079
2023-10-26    103.556831
2023-10-27    103.585583
2023-10-30    103.614335
2023-10-31    103.643087
Length: 247, dtype: float64

 

 

상한가, 하한가 시리즈 타입으로 변환하기


upper2_series = pd.Series(upper2, index=date_index)
lower2_series = pd.Series(lower2, index=date_index)
upper2_series, lower2_series

 

Series

 

 

 

시각화


plt.figure(figsize=(20, 6))
plt.title("시계열 분석 결과 시각화")

### 훈련데이터 그리기 (90%)
plt.plot(train_data, label="train_data")

### 테스트데이터 그리기 (10%)
plt.plot(test_data, label="test_data(예측 전 실제값)", c="b")

### 테스트데이터로 예측한 결과 그리기
plt.plot(fc, label="예측결과", c="r")

### 1년 후 주가 예측 그리기 
plt.plot(fc2, label="1년 후 예측결과", c="g")

### 상한가(상한 바운드), 하한가(하한 바운드) 그리기 
plt.fill_between(lower_series.index, lower_series, upper_series, alpha=.9, color="k")

### 1년 후 예측 → 상한가(상한 바운드), 하한가(하한 바운드) 그리기 
plt.fill_between(lower2_series.index, lower2_seriesupper2_series, alpha=.9, color="c")

plt.legend(loc = "upper left")
plt.show()

 

 

 

 

728x90