Outlier 식별

2024. 3. 13. 23:16금융 데이터 분석

반응형

금융시장에서 Outlier는 그 자체로 중요한 의미를 가질 수도 있고, 어떤 주식에서는 변곡점을 나타낼 수도 있습니다. 또는 그냥 이상현상일 수도 있습니다. 따라서 Outlier처리를 어떻게 할지는 또 다른 어려운 과제지만 먼저 Outlier을 어떻게 식별할지에 대해서 다루어 보도록 하겠습니다.

이번 포스팅에서는 Outlier 식별을 하는데 있어서 고전적인 방법을 다루도록 하겠습니다. 간단하지만 직관적이고 여전히 많이 활용되고 있는 방법입니다.

[평균과 표준편차 활용]

시계열 데이터의 경우 rolling할 window를 정하고 해당 window에서 평균과 표준편차를 활용해서 얼마만큼 평균과 차이가 나는지를 확인하는 것입니다.

일반적으로 정규분포를 생각하면 "평균 + 3*표준편차"보다 특정값이 클 확률은 0.5%도 되지 않을 것이고" 평균 + 2.5표준편차"라고 하더라도 2%가 되지 않을 것입니다. 이러한 특성을 활용해서 평균과 표준편차가 있다면 특정값이 Outlier인지 아닌지를 판별할 수 있을 것입니다.

import pandas as pd
import yfinance as yf
import matplotlib.pyplot as plt

# %%

## 아웃라이어 식별
df = yf.download("AAPL",
                start="2019-01-01",
                end="2020-12-31",
                progress=False)
df["rtn"] = df["Adj Close"].pct_change()
df = df[["rtn"]].copy()

df_rolling = df[["rtn"]].rolling(window=21).agg(["mean", "std"])
df_rolling.columns = df_rolling.columns.droplevel()

df = df.join(df_rolling)
 
N = 2.5
df["upper"] = df["mean"] + N * df["std"]
df["lower"] = df["mean"] - N * df["std"]


df["outlier"] = ((df["rtn"] > df["upper"]) | (df["rtn"] < df["lower"]))


## 그래프
fig, ax = plt.subplots()
df[["rtn", "upper", "lower"]].plot(ax=ax)
ax.scatter(df.loc[df["outlier"]].index,
            df.loc[df["outlier"], "rtn"],
            color="black", label="outlier")
ax.set_title("AAPL's stock returns")
ax.legend(loc="center left", bbox_to_anchor=(1, 0.5))
plt.show()

 

그래프를 보면 까만점이 있는 부분이 outlier이고 해당일에 수익률이 크거나 작은 것을 확인할 수 있습니다.

[중앙값 활용 - Hampel filter]

Hampel filter는 평균이 아니라 중앙값을 활용하는 것이며, 시계열 데이터를 다룰 때 많이 활용되는 방법입니다. 평균대신 중앙값을, 표준편차 대신 MAD(Median Absolute Deviation, 중앙값 절대 편차)를 활용하는데, MAD는 일반적으로 표준편차를 계산할 때 평균이 들어가는데 평균이 아니라 중앙값을 활용하여 편차를 구한 것입니다.

평균과 표준편차와 마찬가지로 rolling할 window size를 정의합니다. 다만 여기서 차이점은 위의 평균과 표준편차 방법은 전에 일어난 21일의 평균을 이용한 것이라면 여기서는 해당일 전과 후를 포함하여 window를 rolling 한다는 것입니다.

예를 들어 2023년 1월 15일에 대해서 window size가 10이라고 가정해보면 편균과 표쥰편차 방법은 1월 6일~15일까지 데이터를 활용하고 Hampel filter는 1월 10일~1월 20일 데이터를 활용한다고 생각하시면 됩니다.

from sktime.transformations.series.outlier_detection import HampelFilter    
    
df = yf.download("AAPL",
                start="2019-01-01",
                end="2020-12-31",
                progress=False)
df["rtn"] = df["Adj Close"].pct_change()    
    

# %% 아웃라이어 식별

hampel_detector = HampelFilter(window_length=10, return_bool=True)
df["outlier"] = hampel_detector.fit_transform(df["Adj Close"])


# %% 그래프
fig, ax = plt.subplots()
df[["Adj Close"]].plot(ax=ax)
ax.scatter(df.loc[df["outlier"]].index, df.loc[df["outlier"], "Adj Close"], color="black", label="outlier")
ax.set_title("AAPL's stock price")
ax.legend(loc="center left", bbox_to_anchor=(1, 0.5))
plt.show()

Hampel filter는 전과 후를 다 보기 때문에 이미 높아진 가격이 형성되었을 때는 사람이 보기에는 직관적으로 peak지만 filter상으로는 outlier로 식별하지 않은 경우도 존재합니다.

참조: https://github.com/erykml/Python-for-Finance-Cookbook-2E

 

반응형