금융 데이터 다루기 > 노이즈 제거(이동평균, 칼만필터(Kalman-filter))

2023. 8. 5. 23:36금융 데이터 분석

반응형

금융 데이터에는 많은 경우 시계열성을 가지고 있고 주가와 같이 하루하루 변동성이 큰 데이터들이 있습니다. 이러한 데이터들을 효과적으로 분석하기 위해서는 Noise를 제거하고 실제로 이 데이터가 가지고 있는 진짜 정보를 추출하는 방법에 대한 기본적인 이해가 필요합니다.

[이동평균]

이동평균은 우리가 잘 알고 있는 방법론이고 실제로 주가의 추세를 볼때 활용하는 20일 이동평균선도 이 이동평균의 개념을 활용한 것입니다. 이동평균은 말그대로 시계열 데이터를 3일, 5일, 10일 등 우리가 정한 집합으로 나누고 해당 집합에서의 평균을 이어서 활용하는 것입니다.

Pandas를 활용해서 너무나도 쉽게 구할 수 있지만, For loop을 활용해서 구하는 방법도 구현을 해보도록 하겠습니다.

import FinanceDataReader as fdr
import pandas as pd
import numpy as np
import OpenDartReader
import requests
from bs4 import BeautifulSoup
import os
import matplotlib.pyplot as plt
import seaborn as sns


df = fdr.DataReader('035720','2022-01-01', '2023-06-30')
df.head(10)                                                                                                                                                                                                                        

price = df["Close"]



## for loop 활용
window_size = 3
moving_average = []
for i in range(len(price) - window_size +1):
    window = price[i:i+window_size]
    moving_average.append(sum(window)/window_size)
 
print(moving_average)


## Pandas 활용
moving_average = price.rolling(3).mean()
print(moving_average)

 

[칼만필터]

또 대푝적으로 시계열 데이터의 노이즈를 제거하기 위한 방법으로 칼만필터(Kalman Filter)가 있습니다.  이름에 필터가 있듯이 우리가 측정한 데이터의 불확실성(노이즈)를 필터링하는 알고리즘으로 이해하시면 됩니다. 칼만필터는 데이터의 선형성과 가우시안 오차를 가정을 하고 있습니다. 따라서 비선형성이 강한 데이터들에 대해서는 확장형 칼만필터를 활용하곤 합니다.

다만 개인적인 생각으로는 특정 상황에서는 분명히 비선형성을 반영이 필요한 상황도 있겠지만, 데이터의 많은 영역들이 선형으로 근사가 가능하고 특히 노이즈를 제거하는 용도로는 충분히 선형성을 가정하고 진행해도 되지 않을까 싶습니다.

칼만필터는 크게 2가지 단계로 이루어집니다. 1) 첫번째 단계는 예측 단계로 현재 상태를 기반으로 다음 상태를 예측하는 단계입니다. 2) 두번째 단계는 업데이트 단계로 예측 단계에서 예측한 상태와 실제로 관측된 상태를 비교하여 예측한 상태를 보정하여 정확성을 더 높입니다.

즉 실제 관측값이 진짜 이 시스템에 존재하는 진짜 상태라고 보지 않고, 칼만필터를 활용해서 진짜 상태를 추정해보는 것입니다. 

칼만필터의 알고리즘 순서는 아래 사이트를 참조하시면 될 것 같습니다. 저는 아래 사이트 내용을 기반으로 Python에서 활용할 수 있게 간략하게 정리해보도록 하겠습니다.

https://forecastegy.com/posts/kalman-filter-for-time-series-forecasting-in-python/ 

여기서 pykalman 패키지를 활용하고자 하는데 , 해당 패키지에서 분석자가 설정해야하는 변수는 F, H, Q, R입니다. 

- F는 상태 전이 행렬로 진짜 상태(x)의 t-1의 값이 t로 변할 때 어떻게 변형되는지를 나타냅니다.

- H는 관측행렬로 진짜 상태(x)가 관측값(z)으로 어떻게 변형되는지를 나타냅니다.

- Q는 해당 시스템의 noise covariance 행렬이며, R은 관측값의 noise covariacne 행렬입니다. 

Python 구현시 사용한 Parameter는 임의로 설정한 값이고 아마 설정한 값에 따라 노이즈 제거 되는 것이 달라질 것 입니다. 파라미터를 어떻게 선정할 수 있는 지에 대해서 pykalman 패키지 자료를 보시면 도움이 될 것 같습니다. 다만 칼만필터의 파라미터(transition matrix)를 정확히 설정하는 일이 매우 어려운 일이므로 일반적으로 Identity matrix의 배수를 많이 활용합니다.(https://pykalman.github.io/#which-unscented-kalman-filter-is-for-me)

from pykalman import KalmanFilter


## Pykalman
F = [1]
H = [1]
Q = 0.01
R = 1

kf = KalmanFilter(transition_matrices = F,
                  observation_matrices = H,
                  transition_covariance = Q,
                  observation_covariance = R,
                  initial_state_mean = 0,
                  initial_state_covariance = 1)

#estimate observe data
filtered_state_mean, filtered_state_covariance = kf.filter(price)

#mapping to df
price = price.reset_index()
price['Kalman Filter'] = filtered_state_mean



#moving average caculating
for window_size in [10,20,30]:
    columns = 'MA_{}'.format(window_size)
    price[columns] = (price["Close"].rolling(window=window_size).mean())

price= price.set_index('Date')


fig, ax = plt.subplots(nrows = 1, figsize = (15,8))
price.iloc[30:].plot(ax = ax, lw=1, title = 'kalman vs ma')

 

칼만필터 결과와 20일 이동평균이랑 비슷한 모습을 보이는데 20일 이동평균 선보다는 좀 더 시계열 변화에 민감하게 반응하는 것 같습니다.

 

[참고]

https://onnons.tistory.com/131

https://minding-deep-learning.tistory.com/39/

https://www.losant.com/blog/implementing-a-kalman-filter-for-better-noise-filtering

 

반응형