본문 바로가기

카테고리 없음

24.06.27 시계열 데이터/ 광주시 기온 데이터 실습/ Mining Algorithm

시계열 데이터 분석

  • 시계열 예측(Times series forecasting)
    • 시계열 데이터: 시간의 흐름에 따른 데이터 
    • 시간 순서대로 수집하거나 정렬한 순차적인(sequential) 데이터를 활용하여 미래 시점의 상태를 예측 
    • eg. 일별 COVID-19 확진자 수 데이터를 통해 앞으로의 확진자 수를 예측 - 적용: 방역 정책을 수립 
  • 시계열 예측의 특징 
    1. 완벽한 예측 불가능
    2. 다변량(multivariate) data: 변수가 여러개 
      • e.g. 의료 데이터에서 환자의 여러 생리학적 변수(혈압, 심박수, 혈당 농도 등)가 함께 측정되는 경우
      • e.g. 여러 지표(온도, 습도, 바람 속도 등)가 한 지역에서 동시에 관측되는 경우가 다변량 데이터의 예
    3. 데이터 set 구성 변형은 어려움
    4. 데이터가 정상성(stationarity)을 띨 때 시계열 예측 정확도가 높음
    5. 시간 종속성(Time dependence) 
      • 시간 순서대로 배열 = 데이터 포인트가 시간적으로 서로 종속적인 관계를 지님 
      • 과거의 데이터가 미래를 예측
    6. 불규칙성(Irregularity)
      • 데이터에 노이즈로 작용하는 예측할 수 있는 변동성이 있음
      • 외부 event 등 예측 불가능한 변화에 의해 발생 
    7. 계절성(Seasonality)
      • 일정 기간을 주기로 반복되는 패턴 
      • e.g. 겨울-난방수요, 여름-냉방수요
    8. 추세(Trend)
      • 데이터에서 장기간에 걸쳐 나타나는 상승 또는 하락 경향
      • e.g. 인구 수
    9. 주기성(Cyclic)
      • 고정된 기간이 아닌 불규칙적인 간격으로 발생 
      • e.g. 경제 호황/불황기 
    10. 정상성(Stationarity)
      • 통계적 속성(평균, 분산, 공분산 등)이 시간에 따라 일정하게 유지되는 성질  = 상승/하락 등 특정 추세가 없는 것  
      • 시간에 따라 평균(mean)과 분산(variance)이 일정하고, 시간 지연에 따른 자기 공분산(auto-covariance)이 시점에 의존하지 않는 성질
      • 즉 시계열 데이터가 일정한 패턴을 가지고 시간이 지나도 변하지 않는다는 것을 의미
      • 시계열 분석의 대부분이 데이터의 정상성을 가정하에 수행
        = 정상성이 없는 데이터는 변환 후에 분석해야 정확도가 높음 (?)
      • 정상성을 갖추지 못했다면 변환 필요 (로그 변환 등) 

실습) 시계열 데이터 Tesla 주가 데이터 

  • yfinance는 Yahoo Finance(주식 및 금융 데이터를 쉽게 가져올 수 있게 해주는 파이썬 라이브러리)에서 Tesla 주가 받기 
    import yfinance as yf
    import pandas as pd
    import matplotlib.pyplot as plt
     
    tsla = yf.download('TSLA', start='2018-01-01', end='2024-06-26')
    tsla
  • 시각화 
    df_tsla = pd.DataFrame(tsla['Close'])
    df_tsla.plot(figsize=(12.2, 6.4))

  •  ADF(Augmented Dickey-Fuller) 검정
    print('ADF test with TSLA time-series')
    ADF_result = adfuller(df_tsla.values)
    #ADF 통계량
    print('ADF Stats: %f' % ADF_result[0])
    #p-값
    print('p-value: %f' % ADF_result[1])
    #임계값
    print('Critical values:' )
    for key, value in ADF_result[4].items():
     print('\t%s: %.4f' % (key, value))

    • yfinance는 Yahoo Finance에서 데이터를 가져오기 위해 만들어진 파이썬 라이브러리
    • 이 라이브러리는 Yahoo Finance API를 사용하여 주식 가격, 재무 보고서 등 다양한 금융 데이터를 쉽게 가져올 수 있게 해줌 (진짜 신기!!)

실습) Multivariate.ipynb 

 

시계열 데이터 분석기법 (가볍게 이런게 있다하고 넘어가기)

  • ARIMA(Auto Regulation Integrated Moving Average)
    • 시계열 데이터의 특성을 설명하고 예측하는 데 도움을 주는 통계적 모델

실습) 광주광역시 기온 데이터를 이용한 기온예측 모델링 

  • 모델링 목적 
    • 30일치의 기온을 입력값으로 사용하여 다음날 31일째 기온을 예측하는 딥러닝 모델을 만들기
    • 설명변수(x): 1~30일 동안의 기온
    • 목표변수(y): 31일의 기온
    • 모델 종류: 회귀분류 
    • 딥러닝 모델 조건: 출력노드 1개(31일 기온의 예측값)/ 입력노드: 30개(30일 간의 기온값) 
  • 데이터 불러오기 
    import pandas as pd
    import numpy as np
    import matplotlib
    import matplotlib.pyplot as plt
    import seaborn as sns


    # 데이터 불러오기
    df = pd.read_csv('/content/temp_mean_gwangju.csv', encoding = 'utf-8', index_col=0) #index_col=0 첫번째열(0번 열)을 인덱스로 지정
    df.head()
  • 데이터 탐색 
    • EDA-Dataframe 탐색
      # Dataframe의 첫번째 행(row) 파악
      df.iloc[0]
      # 열이름 확인
      df.columns
      df.info()
      help(df.info())
      # 기초통계량 확인
      df.describe()
      # count: 비어있지않은 data의 개수
      # 25/ 50/ 75%: 사분위 값
    • 사분위값
  • 데이터 전처리 
    • 결측치 확인
      df.isnull()
      df.isnull().values.sum() #null의 개수
      # 결측치 시각화
      plt.figure(figsize=(15,5))
      sns.heatmap(df.isnull(), cbar=False,);  
      # cbar 컬러 바(color bar) 표시 여부
      # shift-tab 단축키를 이용해서 함수의 독스트링 확인
      plt.show()
      #결측치를 흰색으로, 결측치가 아닌 값을 검은색
       
      • 결측치 채우기
        # 원본 data를 copy해서 결측치 채우기
        df_fillna = df.copy()
        # ffil=forward fill, 앞의 값(전날)을 가져와서 채우라
        # 온도의 경우 전일과 온도 유사할 것
        df_fillna.fillna(method='ffill').tail(3)
         
      • Data transpose(행열 변환): 특정 변수에 대해 분석하기 위함 
        df.values.shape
        # 행열 변환
        df.T.values.shape
      • 차원 변경
        # 2차원 -> 1차원으로 만들기
        # 월 별로 2차원으로 array가 되어있으니 1차원으로 변경 (x: 30일치 값 넣고 y: 31일 값 나오고 해야하니)
        # 이미지(해상도: e.g. 2560 * 1440: 가로/세로의 pixel 수)도 2차원 값
        # 결측치 제거
        temp_include_nan = df.T.values.flatten()
        temp_include_nan.shape
        temp = temp_include_nan[~np.isnan(temp_include_nan)]
        # temp_include_nan 배열에서 결측치가 아닌 값을 선택해서 temp 변수에 할당하는 코드 
        # np.isnan(temp_include_nan): temp_include_nan 배열에서 각 원소가 결측치인지 아닌지 판별하는 조건
        # ~: not의미 
        # ~np.isnan(temp_include_nan): 결측치가 아니면 True, 맞으면 False로 반환 
        #   temp_include_nan[~np.isnan(temp_include_nan)]: temp_include_nan 에서 결측치가 아닌(True) 값으로 채우는 새로운 temp를 생성 
  • 모델링  
    import tensorflow
    from tensorflow.keras.models import Sequential
    from tensorflow.keras.layers import Dense
     
    # input: 30일
    steps = 30

    # 예측기간: 15일로 설정
    forecast_terms = 15
     
    #temp: 원본 시계열 데이터 (일반적으로 Pandas DataFrame이나 Numpy 배열)
    #steps: 각 입력 샘플이 포함할 시계열 데이터의 길이 (슬라이딩 윈도우의 크기)
    #forecast_terms: 예측하려는 미래 시계열 데이터의 길이
     
    # 학습 데이터 생성
    x_train = []
    for i in range(len(temp) - forecast_terms - steps):    
        x_train.append(temp[i:i+steps])
    # for 반복문을 통해 temp에서 학습 데이터의 입력 데이터인 연속된 30일치 데이터를 추출해서 x_train 리스트에 추가  # len(temp): temp의 길이, temp 리스트에 포함된 데이터의 개수를 의미 
    # forecast_terms: 예측 기간으로 설정한 값
    # steps: 입력기간으로 설정한 값
     
    x_train = np.array(x_train)
    y_train = temp[steps:len(temp)-forecast_terms]
    # temp 리스트에서 예측기간 이후(step 이후)부터 예측기간 전(len(temp)-forecase_terms)까지의 데이터를 y_train으로 설정

    # 테스트 데이터 생성
    x_test = []
    for i in range(forecast_terms):
        x_test.append(temp[-(steps+forecast_terms)+i:-forecast_terms+i])

    x_test = np.array(x_test)
    y_test = temp[-forecast_terms:]

    print("x_train:\n", x_train)
    print("\ny_train:", y_train)
    print("\nx_test:\n", x_test)
    print("\ny_test:", y_test)
     
     



    input_node = 
    30

    output_node = 1
     
    model_simple = Sequential()
    model_simple.add(Dense(output_node, input_shape=(input_node, )))
    # Dense=fully connected network=모든 노드가 연결된 것
     
    model_simple.compile(loss="mse", optimizer = 'adam')
    model_simple.summary()
     
    model_simple_hist = model_simple.fit(x_train,
                                         y_train,
                                         epochs=10,
                                         batch_size=100,
                                         validation_split=0.2) # hist=histogram


  • 단층 신경망 설
    input_node = 30

    output_node = 1
     
    model_simple = Sequential()
    model_simple.add(Dense(output_node, input_shape=(input_node, )))
    # Dense=fully connected network=모든 노드가 연결된 것
    model_simple.compile(loss="mse", optimizer = 'adam')
    model_simple.summary()
     
    model_simple_hist = model_simple.fit(x_train,
                                         y_train,
                                         epochs=10,
                                         batch_size=100,
                                         validation_split=0.2) # hist=histogram
  • 성능평가를 위한 시각화
    plt.plot(model_simple_hist.history["loss"], label="train_loss") # 손실함수 값
    plt.plot(model_simple_hist.history["val_loss"], label="val_loss")
    # 검증손실함수
    # 모델이 학습에 사용되지 않은 검증 데이터에 대해 예측한 값과 실제값 사이의 차이
    # 학습과정 중 모델의 성능 평가를 위해 사용
     
    plt.xlabel("epoch")
    plt.ylabel("loss")
    plt.legend();
  • 정확도 분석
    model_simple.predict(x_test)
    pred_simple = model_simple.predict(x_test).flatten()
     
    acc = np.sum(np.abs(y_test - pred_simple) <= 0.5)/len(y_test)
    acc_train = np.sum(np.abs(y_train - model_simple.predict(x_train).flatten()) <= 0.5)/len(y_train)

    print("단층 신경망 테스트 데이터 정확도: ", np.round(acc, 2),"%")
    print("단층 신경망 훈련 데이터 정확도: ", np.round(acc_train, 2),"%")

    # 초기 가중치 랜덤으로 정확도가 돌릴때마다 다름 -> random seed를 정하든지, 계속 돌리든지하면 같아짐
     
  • 정확도 시각화
    plt.figure(figsize=(15,5))
    plt.plot(y_test, c="C0", marker="o", label="real")
    plt.plot(pred_simple, c="C1", marker="s", label="predict")
    plt.xticks(range(15), labels=list(range(17,32)))
    plt.legend();
     
    plt.figure(figsize=(15,5))
    plt.plot(y_test, c="C0", marker="o", label="real")

    #정답 범위
    plt.fill_between(range(15), y_test-0.5, y_test+0.5, color="C0", alpha=0.3)

    plt.plot(pred_simple, c="C1", marker="s", label="predict")
    plt.xticks(range(15), labels=list(range(17,32)))
    plt.legend();