콘텐츠로 이동
Data Prep
상세

Anomaly Detection (이상 탐지)

메타 정보

항목 내용
분류 Unsupervised / Semi-Supervised / Data Quality
핵심 논문 "Isolation Forest" (ICDM 2008), "Deep One-Class Classification" (ICML 2018), "A Unifying Review of Deep and Shallow Anomaly Detection" (IEEE 2021)
주요 저자 Fei Tony Liu, Kai Ming Ting, Zhi-Hua Zhou (Isolation Forest); Lukas Ruff et al. (Deep SVDD); Varun Chandola et al. (Survey)
핵심 개념 정상 데이터의 분포에서 벗어난 관측치(outlier, novelty)를 탐지
관련 분야 Fraud Detection, Predictive Maintenance, Network Intrusion, Quality Control

정의

Anomaly Detection은 데이터셋에서 대다수의 정상(normal) 패턴과 현저히 다른 관측치를 식별하는 작업이다. 이상치(anomaly)는 통계적 분포, 거리, 밀도, 또는 학습된 표현 공간에서 정상 데이터와 구별된다.

핵심 가정: 이상치는 (1) 전체 데이터의 극소수를 차지하고, (2) 정상 데이터와 특성이 상이하다.

이상 탐지의 분류 체계

이상의 유형

Point Anomaly (점 이상)
  개별 데이터 포인트가 나머지와 현저히 다름
  예: 신용카드 거래에서 갑작스러운 고액 결제

Contextual Anomaly (맥락 이상)
  특정 맥락에서만 이상으로 판단됨
  예: 여름에 난방비가 급증 (겨울이면 정상)

Collective Anomaly (집합 이상)
  개별적으로는 정상이나 모이면 이상 패턴
  예: 네트워크에서 특정 시간대에 반복되는 접속 패턴

학습 패러다임

감독 학습 (Supervised)
  정상 + 이상 레이블 모두 존재
  -> 분류 문제로 접근 (class imbalance 처리 필요)
  제한: 이상 레이블 확보가 현실적으로 어려움

준지도 학습 (Semi-Supervised)
  정상 데이터만으로 학습 (One-Class Learning)
  -> 정상 분포를 모델링하고, 벗어나면 이상으로 판단
  대표: One-Class SVM, Deep SVDD, Autoencoder

비지도 학습 (Unsupervised)
  레이블 없이 데이터 구조만으로 탐지
  -> 밀도, 거리, 고립성 등 데이터 고유 특성 활용
  대표: Isolation Forest, LOF, DBSCAN

주요 알고리즘

1. 통계 기반 (Statistical)

데이터가 특정 분포를 따른다는 가정 하에 이상치를 탐지한다.

방법 원리 장점 한계
Z-Score 평균에서 표준편차 기준 거리 단순, 해석 용이 정규분포 가정
IQR (Interquartile Range) Q1 - 1.5IQR ~ Q3 + 1.5IQR 범위 밖 분포 가정 불필요 다변량 부적합
Mahalanobis Distance 공분산 고려한 거리 상관관계 반영 정규분포 가정, 고차원 불안정
Grubbs' Test 통계 검정 기반 단일 이상치 탐지 이론적 근거 명확 하나씩만 탐지
import numpy as np
from scipy import stats

# Z-Score 기반 이상 탐지
def detect_zscore(data, threshold=3.0):
    z_scores = np.abs(stats.zscore(data))
    return z_scores > threshold

# Mahalanobis Distance
def mahalanobis_anomaly(X, threshold_percentile=97.5):
    mean = np.mean(X, axis=0)
    cov = np.cov(X.T)
    cov_inv = np.linalg.inv(cov)

    distances = []
    for x in X:
        diff = x - mean
        d = np.sqrt(diff @ cov_inv @ diff)
        distances.append(d)

    threshold = np.percentile(distances, threshold_percentile)
    return np.array(distances) > threshold

2. 거리/밀도 기반 (Distance/Density)

데이터 포인트 간의 거리 또는 지역 밀도를 활용한다.

LOF (Local Outlier Factor)

Breunig et al. (2000)이 제안. 각 포인트의 지역 밀도를 이웃의 밀도와 비교한다.

LOF 계산 과정:

1. k-거리 (k-distance):
   포인트 p에서 k번째 가까운 이웃까지의 거리

2. 도달 거리 (reachability distance):
   reach-dist_k(p, o) = max(k-distance(o), d(p, o))

   -> 너무 가까운 이웃의 영향을 평활화

3. 지역 도달 밀도 (local reachability density):
   lrd_k(p) = 1 / (avg reach-dist of k-neighbors)

4. LOF 계산:
   LOF_k(p) = avg(lrd_k(o) / lrd_k(p)) for o in N_k(p)

   LOF ~ 1   : 이웃과 밀도가 유사 (정상)
   LOF >> 1  : 이웃보다 밀도가 낮음 (이상)
   LOF << 1  : 이웃보다 밀도가 높음 (정상)

kNN Distance

k번째 이웃까지의 거리 또는 k개 이웃의 평균 거리를 이상 점수로 사용한다. LOF보다 단순하지만 밀도 변화에 덜 적응적이다.

from sklearn.neighbors import LocalOutlierFactor

# LOF
lof = LocalOutlierFactor(n_neighbors=20, contamination=0.05)
labels = lof.fit_predict(X)  # -1: anomaly, 1: normal
scores = -lof.negative_outlier_factor_  # 높을수록 이상

3. Isolation Forest

Liu, Ting, Zhou (ICDM 2008)이 제안한 알고리즘으로, 이상 탐지에 대한 근본적으로 다른 접근법이다. 정상 데이터를 프로파일링하는 대신, 이상치가 고립(isolate)하기 쉽다는 성질을 직접 활용한다.

핵심 직관:

이상치는 정상 데이터보다 "고립하기 쉽다"
-> 무작위 분할 시 적은 횟수만에 분리됨

정상 데이터:                 이상 데이터:
+------------------+         +------------------+
|  . . . . . . .   |         |  . . . . . . .   |
|  . . . . . . .   |         |  . . . . . . .   |
|  . . . . . . .   |         |  . . . . . . .   |
|  . . . . . . .   |         |  . . . x . . .   |  <- x를 분리하려면
|  . . . . . . .   |         |  . . . . . . .   |     많은 분할 필요
+------------------+         +------------------+

                              +------------------+
                              |                  |
                              |         *        |  <- *는 한두 번의
                              |  . . . . . . .   |     분할로 분리 가능
                              |  . . . . . . .   |
                              +------------------+

알고리즘

Isolation Forest 구축:

1. 서브샘플링: 전체 데이터에서 psi개 샘플 추출 (기본 256)
2. Isolation Tree 구축:
   a. 무작위로 특성(feature) 하나 선택
   b. 해당 특성의 min~max 사이에서 무작위 분할점 선택
   c. 분할점 기준으로 좌/우 노드로 데이터 분배
   d. 각 노드에 1개 포인트만 남거나 max_depth 도달 시 종료
3. 앙상블: t개의 Isolation Tree 구축 (기본 100)

이상 점수 (Anomaly Score):

  s(x, n) = 2^(-E(h(x)) / c(n))

  E(h(x)) : 모든 트리에서 x의 평균 경로 길이
  c(n)     : BST 평균 경로 길이 (정규화 상수)

  s -> 1   : 이상 (경로가 짧음)
  s -> 0.5 : 판단 어려움
  s -> 0   : 정상 (경로가 김)

특성

특성 설명
시간 복잡도 O(t * psi * log(psi)) -- 선형에 가까움
메모리 O(t * psi) -- 서브샘플링으로 효율적
스케일링 고차원, 대규모 데이터에 적합
파라미터 n_estimators (트리 수), max_samples (서브샘플 크기), contamination
from sklearn.ensemble import IsolationForest

# Isolation Forest
iso_forest = IsolationForest(
    n_estimators=100,
    max_samples=256,
    contamination=0.05,
    random_state=42
)
labels = iso_forest.fit_predict(X)  # -1: anomaly, 1: normal
scores = -iso_forest.decision_function(X)  # 높을수록 이상

4. One-Class SVM

Scholkopf et al. (2001). 데이터를 고차원 특성 공간에 매핑한 후, 원점에서 최대 마진으로 분리하는 초평면을 찾는다.

One-Class SVM 원리:

입력 공간          커널 매핑           특성 공간
  . . .            phi(x)           .  .
  . . .           ------>          .  .  .
  . *              커널             . *. .
                                    \---/
                                   초평면으로
                                  원점과 분리

목적 함수:
  min  (1/2)||w||^2 + (1/(v*n)) * sum(xi_i) - rho
  s.t. w . phi(x_i) >= rho - xi_i,  xi_i >= 0

v (nu): 이상치 비율의 상한/서포트 벡터 비율의 하한
from sklearn.svm import OneClassSVM

# One-Class SVM (RBF 커널)
ocsvm = OneClassSVM(kernel='rbf', gamma='scale', nu=0.05)
ocsvm.fit(X_train)  # 정상 데이터만
labels = ocsvm.predict(X_test)  # -1: anomaly, 1: normal

5. Autoencoder 기반

정상 데이터로 Autoencoder를 학습시킨 후, 재구성 오차(reconstruction error)가 큰 데이터를 이상으로 판단한다.

Autoencoder 이상 탐지:

입력 x  --[Encoder]--> z (잠재 표현) --[Decoder]--> x_hat (재구성)

정상 데이터:  x ≈ x_hat  ->  ||x - x_hat||^2 작음
이상 데이터:  x ≠ x_hat  ->  ||x - x_hat||^2 큼

재구성 오차 분포:

  정상:  |###########|
  이상:                        |####|
         ------+---------------+---------> 재구성 오차
            낮음    threshold    높음

Variational Autoencoder (VAE)

VAE는 잠재 공간에 확률적 구조를 부여하여 더 견고한 이상 탐지가 가능하다. 이상 점수로 재구성 오차 + KL divergence 또는 ELBO를 사용한다.

import torch
import torch.nn as nn

class AnomalyAutoencoder(nn.Module):
    def __init__(self, input_dim, latent_dim=32):
        super().__init__()
        self.encoder = nn.Sequential(
            nn.Linear(input_dim, 128),
            nn.ReLU(),
            nn.Linear(128, 64),
            nn.ReLU(),
            nn.Linear(64, latent_dim)
        )
        self.decoder = nn.Sequential(
            nn.Linear(latent_dim, 64),
            nn.ReLU(),
            nn.Linear(64, 128),
            nn.ReLU(),
            nn.Linear(128, input_dim)
        )

    def forward(self, x):
        z = self.encoder(x)
        x_hat = self.decoder(z)
        return x_hat

    def anomaly_score(self, x):
        x_hat = self.forward(x)
        return torch.mean((x - x_hat) ** 2, dim=1)

# 학습 (정상 데이터만)
model = AnomalyAutoencoder(input_dim=30)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
criterion = nn.MSELoss()

for epoch in range(100):
    x_hat = model(X_train_normal)
    loss = criterion(x_hat, X_train_normal)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

# 추론
scores = model.anomaly_score(X_test).detach().numpy()
threshold = np.percentile(scores, 95)
anomalies = scores > threshold

6. Deep SVDD (Deep Support Vector Data Description)

Ruff et al. (ICML 2018). One-Class SVM의 딥러닝 확장으로, 신경망이 정상 데이터를 특성 공간의 하나의 초구(hypersphere) 중심 근처에 매핑하도록 학습한다.

Deep SVDD 원리:

입력 공간                특성 공간 (신경망 매핑)

  . . . .               . .  .
  . . * .   --phi-->    . c .     c: 중심
  . . . .              .  . .
  . .   .                 |R|     R: 반경

                        경계 밖 = 이상

목적 함수:
  min  (1/n) * sum(||phi(x_i; W) - c||^2) + (lambda/2) * ||W||^2

  정상 데이터: c 근처에 매핑 -> 손실 작음
  이상 데이터: c에서 멀리 매핑 -> 손실 큼 (탐지)

7. 시계열 이상 탐지

시계열 데이터는 시간적 의존성이 존재하므로 특화된 방법이 필요하다.

방법 원리 적용
ARIMA Residuals 예측 잔차의 이상 패턴 단변량 시계열
Prophet Anomaly 트렌드/계절성 분해 후 잔차 분석 비즈니스 시계열
LSTM-AE LSTM Autoencoder로 시퀀스 재구성 다변량 시계열
Transformer-based Self-attention 기반 시계열 이상 탐지 장기 의존성
Matrix Profile 서브시퀀스 간 거리 프로파일 모티프/디스코드 탐지
# LSTM Autoencoder for Time Series Anomaly Detection
import torch.nn as nn

class LSTMAutoencoder(nn.Module):
    def __init__(self, n_features, hidden_dim=64, n_layers=2):
        super().__init__()
        self.encoder = nn.LSTM(
            n_features, hidden_dim, n_layers, batch_first=True
        )
        self.decoder = nn.LSTM(
            hidden_dim, hidden_dim, n_layers, batch_first=True
        )
        self.output_layer = nn.Linear(hidden_dim, n_features)

    def forward(self, x):
        # x: (batch, seq_len, n_features)
        _, (h, c) = self.encoder(x)

        # Decoder: 인코더의 마지막 hidden state를 반복
        seq_len = x.size(1)
        decoder_input = h[-1].unsqueeze(1).repeat(1, seq_len, 1)
        decoder_out, _ = self.decoder(decoder_input)

        reconstruction = self.output_layer(decoder_out)
        return reconstruction

방법 선택 가이드

데이터 특성에 따른 알고리즘 선택:

데이터 크기?
  |
  +-- 소규모 (< 10K)
  |     |
  |     +-- 고차원? -- Yes --> One-Class SVM (RBF)
  |     |           -- No  --> LOF / kNN
  |
  +-- 중규모 (10K ~ 1M)
  |     |
  |     +-- 해석성 필요? -- Yes --> Isolation Forest
  |     |               -- No  --> Autoencoder
  |
  +-- 대규모 (> 1M)
        |
        +-- Isolation Forest (서브샘플링으로 확장)
        +-- Streaming: Half-Space Trees, RRCF
상황 추천 방법 이유
정형 데이터, 빠른 프로토타입 Isolation Forest 파라미터 적음, 빠름, 견고함
비선형 복잡한 패턴 Autoencoder / VAE 표현 학습 능력
이미지 이상 CNN Autoencoder, PatchCore 공간적 패턴 캡처
시계열 LSTM-AE, Transformer 시간적 의존성 모델링
그래프/네트워크 GNN-based, Spectral 구조적 이상 탐지
레이블 일부 존재 Deep SAD, DevNet 준지도 학습 활용
해석성 중요 Isolation Forest + SHAP 특성 기여도 설명 가능

평가 지표

이상 탐지는 극단적 클래스 불균형(정상 >> 이상)이므로 accuracy는 부적절하다.

지표 설명 용도
AUROC ROC 곡선 아래 면적 전반적 분리 능력
AUPRC PR 곡선 아래 면적 불균형 데이터에 더 적합
F1-Score Precision과 Recall의 조화 평균 임계값 설정 후 평가
Precision@k 상위 k개 중 실제 이상 비율 실무에서 리소스 할당
AUROC vs AUPRC:

극단적 불균형 (이상 0.1%):
  AUROC = 0.95 -> "좋아 보이지만..."
  AUPRC = 0.30 -> 실제로는 많은 오탐 존재

  -> AUPRC가 더 현실적인 평가
from sklearn.metrics import roc_auc_score, average_precision_score

# 평가
auroc = roc_auc_score(y_true, anomaly_scores)
auprc = average_precision_score(y_true, anomaly_scores)
print(f"AUROC: {auroc:.4f}, AUPRC: {auprc:.4f}")

실전 파이프라인 예시

import numpy as np
import pandas as pd
from sklearn.ensemble import IsolationForest
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import classification_report

# 1. 데이터 로드 및 전처리
data = pd.read_csv("transactions.csv")
features = ['amount', 'frequency', 'time_since_last', 'distance']
X = data[features].values

# 2. 스케일링 (거리/밀도 기반 방법에 중요)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 3. 다중 모델 앙상블
from sklearn.neighbors import LocalOutlierFactor

# 모델 1: Isolation Forest
iso = IsolationForest(contamination=0.02, random_state=42)
iso_scores = -iso.fit(X_scaled).decision_function(X_scaled)

# 모델 2: LOF
lof = LocalOutlierFactor(n_neighbors=20, contamination=0.02)
lof.fit_predict(X_scaled)
lof_scores = -lof.negative_outlier_factor_

# 4. 점수 정규화 및 앙상블
from sklearn.preprocessing import MinMaxScaler

iso_norm = MinMaxScaler().fit_transform(iso_scores.reshape(-1, 1)).ravel()
lof_norm = MinMaxScaler().fit_transform(lof_scores.reshape(-1, 1)).ravel()

# 가중 평균 앙상블
ensemble_scores = 0.5 * iso_norm + 0.5 * lof_norm

# 5. 임계값 설정 및 탐지
threshold = np.percentile(ensemble_scores, 98)
anomalies = ensemble_scores > threshold

print(f"탐지된 이상: {anomalies.sum()} / {len(anomalies)}")

최근 동향 (2024-2025)

트렌드 설명
LLM 기반 이상 탐지 텍스트 로그, 코드 등에서 LLM의 맥락 이해력 활용
Foundation Model for AD 다양한 도메인에 전이 가능한 범용 이상 탐지 모델
Self-Supervised Pretext 보조 태스크(회전 예측, 대조 학습)로 정상 표현 학습
Graph Neural Network AD 그래프 구조 데이터(소셜 네트워크, 금융 거래)에서의 이상 탐지
Explainable AD SHAP, attention 기반 이상 원인 설명
Few-Shot AD 극소량의 이상 샘플로 탐지 성능 향상

참고 문헌

  1. Liu, F. T., Ting, K. M., & Zhou, Z.-H. (2008). Isolation Forest. ICDM 2008.
  2. Breunig, M. M., et al. (2000). LOF: Identifying Density-Based Local Outliers. SIGMOD 2000.
  3. Scholkopf, B., et al. (2001). Estimating the Support of a High-Dimensional Distribution. Neural Computation.
  4. Ruff, L., et al. (2018). Deep One-Class Classification. ICML 2018.
  5. Chandola, V., Banerjee, A., & Kumar, V. (2009). Anomaly Detection: A Survey. ACM Computing Surveys.
  6. Pang, G., et al. (2021). Deep Learning for Anomaly Detection: A Review. ACM Computing Surveys.
  7. Schmidl, S., et al. (2022). Anomaly Detection in Time Series: A Comprehensive Evaluation. VLDB 2022.