Programming/Python

PyOD 라이브러리로 간단하게 이상치 탐지하기

어쩌다통계 2022. 10. 19. 01:05
728x90

이 글이 도움되셨다면 광고 클릭 부탁드립니다 : )

이상치 탐지를 하다 보면 데이터에 맞는 방법들이 있어 여러 가지 방법들을 적용해보는 편인데, 아무래도 일관성이 떨어지다 보니 이런 방법론들이 모여있는 라이브러리가 없을까?! 하고 찾던 중 PyOD를 발견하게 되어 정리를 해봅니다.

풀네임이 Python Outlier Detection인 PyOD는 다변량 데이터에 적용 가능한 이상치 탐지 방법론들이 30개 이상 구현되어 있는 라이브러리입니다.
가장 기본적인 LOF부터 HBOS, OCSVM, IForest와 제가 좋아하는 AutoEncoder와 VAE까지 방법론이 너무 많아 우선 여기 있는 이상치 탐지 방법론부터 공부해봐도 좋겠다 생각이 들었습니다.
예전에 나온 방법론뿐 아니라 2022년에 나온 ECOD라는 확률 기반 탐지 방법도 있는 것 보면 꾸준히 유지 보수가 되는 라이브러리 같았습니다.

본 포스팅에서는 간단하게 PyOD를 살펴보고 캐글의 Credit Card Fraud Detection 데이터로 샘플 코드를 작성하여 간단한 테스트를 해보겠습니다.

 


0. PyOD?!

 

우선 PyOD의 documentaion에서 소개하는 PyOD의 특징/ 장점은 아래와 같습니다.

  • Unified APIs, detailed documentation, and interactive examples across various algorithms.
  • Advanced models, including classical ones by distance and density estimation, latest deep learning methods, and emerging algorithms like ECOD.
  • Optimized performance with JIT and parallelization using numba and joblib.
  • Fast training & prediction with SUOD [AZHC+21].

이 외에도 2017년도부터 수많은 academic research나 commercial product에서 활용도가 높고 다운로드만 600백만 번 정도 되었다고 합니다.

간단한 소개뿐만 아니라 PyOD가 구현한 방법론들이 Type 별로 잘 구분되어 있어 방법론을 몰라도 본인이 원하는 알고리즘을 간단하게 적용해볼 수 있습니다. 각 알고리즘의 레퍼런스도 링크를 걸어둬 이상치 탐지 학습용으로도 좋은 라이브러리입니다.


이 라이브러리가 좋았던 이유 중 하나는 Benchmark가 잘 정리되어 있다는 점이었는데요.
보통 성능은 다른 라이브러리에서도 가끔 봤는데 속도도 같이 비교해줘서 실무자 입자에서는 아주아주 고마웠습니다.
물론 데이터마다 다르긴 하겠지만 제 일을 대신 해준 느낌이랄까요...?ㅎㅎ


 

1. Credit Card Fraud Detection 실습

1.1 Data 소개

이번 예제에서 사용할 데이터는 캐글에서 제공하는 신용카드 거래 데이터입니다.
2일 동안 발생한 284,807건의 거래 중 492건이 사기 거래(0.172%)이고 변수는 PCA로 가공된 28개의 변수와 시간, 금액 그리고 타겟 클래스 변수가 있습니다.
다른 모델을 사용하지 않고 PyOD의 간단한 알고리즘을 사용하여 사기거래를 이상치로 분류해보려고 합니다.

 

1.2 적용해 볼 이상치 탐지 알고리즘

최대한 간단하고 명료한 방법론을 먼저 시도해보려고 합니다.

 

1.2.1. LOF, Identifying Density-Based Local Outliers

  • 근처에 있는 데이터의 분포에서 얼마나 떨어져 있는지 판단
  • 아래 그림의 $O_1$은 일반적인 거리/분포 기반 방법으로도 이상치로 판단하겠지만,
  • $O_2$는 이상치로 판단하기 어려울 수 있음 -> 근처에 있는 데이터만 이용해서 이상치 판단


1.2.2. HBOS, Histogram-based Outlier Score

  • 각 변수 별 히스토그램을 그려 outlier score를 계산
  • 특정 데이터 포인트가 대부분의 변수에서 이상값이라면 실제 이상값일 가능성이 높을 거라는 가설
  • 각 변수 별 히스토그램의 높이의 합으로 outlier score 계산
  • 변수 간 독립 가정, 변수가 많아도 빠르게 적용 가능

 

1.2.3. PCA 기반 이상치 탐지

  • PCA는 데이터의 분산을 최대로 하는 축을 찾아내어 projection, 선형적 차원 축소
  • 축소된 피처셋을 원본 차원 수로 다시 구성? 하면 재구성 오차 발생(reconstructure error) -> 이상치는 재구성 오차가 큼
  • 이상치는 가장 드물게 발생하고 정상 데이터와 달라서 projection 할 때 해당 정보를 반영하지 못함


1.2.4. isolation forest

  • 정상 군집에서 떨어진 데이터 $x_o$는 적은 수의 공간 분할만으로 isolation 가능
  • 의사결정나무를 몇 회 타고 내려가서 고립되는 지를 기준으로 정상치와 이상치 분리

 

1.3 PyOD 설치 및 알고리즘 적용

PyOD를 설치하고 사용할 이상치 탐지 모델을 불러옵니다.

# import models
!pip install pyod

from pyod.models.lof import LOF
from pyod.models.hbos import HBOS
from pyod.models.pca import PCA
from pyod.models.iforest import IForest

import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import precision_score, recall_score, f1_score, accuracy_score

사용할 데이터를 캐글에서 다운로드하여 불러와서 봤더니 Amount 변수만 범위가 너무 넓어 간단하게 MinMax 변환하여 진행합니다.
너무 많으면 오래 걸리니 10,000개만 랜덤 추출하여 적용해보겠습니다.

# load data
data0 = pd.read_csv('creditcard.csv')
data0.head(2)

data1 = data0.sample(n=10000, random_state=1025)
X_train = data1.drop(columns=['Time','Class'])
y_train = data1[['Class']]

# standardize
scaler = MinMaxScaler(feature_range=(0,1))
X_train[['Amount']] = scaler.fit_transform(X_train[['Amount']])

한 번에 테스트하기 좋게 딕셔너리로 정리하고 이상치 탐지를 해봅니다.
PyOD의 모델들은 outlier_fraction이라는 parameter가 있는데 default값은 0.1이라서 실제 이상치 비율인 0.1727%으로 설정합니다.
실제 분석을 할 때는 알려진 이상치의 비율이 없다면 outlier_fraction 설정하는 데에도 여러 추가 분석이 필요할 것 같네요.

# setting parameters
random_state = np.random.RandomState(1025)
outliers_fraction = 0.0014
# Define seven outlier detection tools to be compared
classifiers = {
        'LOF': LOF(contamination=outliers_fraction),
        'HBOS': HBOS(contamination=outliers_fraction),
        'PCA': PCA(contamination=outliers_fraction),
        'Isolation Forest': IForest(contamination=outliers_fraction,random_state=random_state),
}

# model fitting
for i, (clf_name, clf) in enumerate(classifiers.items()):
    clf.fit(X_train)
    y_pred = clf.labels_
    print(clf_name)
    print('accuracy : ',round(accuracy_score(y_train,y_pred),3))
    print('precision : ',round(precision_score(y_train,y_pred),3))
    print('recall : ',round(recall_score(y_train,y_pred),3))
    print('f1 : ',round(f1_score(y_train,y_pred),3))
    print('-------------------')
LOF accuracy : 0.998 precision : 0.429 recall : 0.429 f1 : 0.429
-------------------
HBOS accuracy : 0.998 precision : 0.143 recall : 0.143 f1 : 0.143
-------------------
PCA accuracy : 0.998 precision : 0.286 recall : 0.286 f1 : 0.286
-------------------
Isolation Forest accuracy : 0.998 precision : 0.286 recall : 0.286 f1 : 0.286
-------------------


train 성능이 이 정도라면 단독으로 이상치 탐지하기에는 너무 단순한 방법인가 싶지만 이런 방법론이 필요한 순간이 많기 때문에 PyOD 라이브러리를 당분간 애용하게 될 것 같습니다 : )

반응형