본문 바로가기

DEVELOP_NOTE/MLOps

Drift를 감지하는 방법 (1) Data Drift Detection

지난 포스팅에서는 Model Drift의 개념과 발생원인에 대해서 정리해보았다.

 

> Model Drift의 개념과 원인 (+ Data Drift, Label Drift, Concept Drift)
https://familia-89.tistory.com/69

 

 

잠깐 리마인드해보자면,

model drift가 발생했을때, 가장 대표적인 원인으로는 data drift, label drift, concept drift를 꼽을 수 있었다.

data drift는 학습당시의 데이터분포와 프로덕트단에서 input되는 데이터의 분포가 상이할 때 발생하는 성능 저하 현상이다.

label drift는 target데이터 분포가 학습당시와 프로덕트 단에서 차이가 있을 경우, 발생하는 성능 저하 현상이다.

마지막으로, concept drift는 feature와 target간의 관계가, 학습당시와 달라질 경우 발생할 수 있는 성능 저하 현상이다.

 

다만, 실제 프로덕트에서  위와 같이 model drift가 발생했을때, 원인을 정확히 정의하기 위해서는 그에 맞는 적절한 검증법을 통한

실험으로써 drift의 원인을 찾을 수 있다. 

 

오늘은 Data Drift를 detection할 수 있는 검증방법들을 살펴보자.

 

Data/Label Drift Detection

Statistical Tests(통계적 검정)

: 학습데이터와 프로덕트단에서 input되는 데이터 집합간의 분포차이를 수치화하여 이상여부를 판단하는 방법이다.

 

1. Kolmogorov-Smirnov Test(이하 KS Test)

KS Test 검증법은 두 표본내의 각각의 원소(포인트)에 대한 누적분포를 계산한 후, 두 집합내의 동일한 포인트간의 누적분포 수치 차이를 구한 후, 그 중 '최대 누적분포 차이'를 통해, 두개의 표본이 같은 같은 분포를 가지는지를 검증하는 방법이다.

여기서 *누적분포에 대해서 잠시 알아보자.

 

  • 표본 A : [1,2,3,4,5]
  • 표본 B : [2,3,4,5,6]

위와 같은 두개의 표본이 있을때, 각 표본의 누적분포는 아래와 같이 구할 수 있다.

  • 표본A의 누적분포
    • 1이하의 값의 비율 : 1/5 = 0.2
    • 2이하의 값의 비율 : 2/5 = 0.4
    • 3이하의 값의 비율 : 3/5 = 0.6
    • 4이하의 값의 비율 : 4/5 = 0.8
    • 5이하의 값의 비율 : 5/5 = 1.0
  • 따라서 표본A의 누적분포는 ->  [0.2, 0.4, 0.6, 0.8, 1.0]으로 구할 수 있다.
  • 동일한 방법으로 계산한 표본 B의 누적분포는  [0.2, 0.4, 0.6, 0.8, 1.0] 이다.

결국, 분포의 각 포인트별 누적분포를 비교했을때, '최대 누적분포'는 0이므로, 두 분포간의 차이는 없다고 판단할 수 있다.

python에서는 KS Test를 진행할 수 있는 라이브러리를 제공하고 있다.

import numpy as np
import scipy.stats as stats

# 샘플 데이터 생성
np.random.seed(0)
train_set = np.random.normal(0, 1, 1000)   # 초기 데이터셋 (정규 분포)
product_set = np.random.normal(0.1, 1.1, 1000)    # 새로운 데이터셋 (분포 약간 다르게)
ks_statistic, p_value = stats.ks_2samp(train_set, product_set)
print(f"KS Test Score: {ks_statistic}")

[output] KS Test Score: 0.086

 

 

Population Stability Index (PSI)

: PSI 또한 두 집단간 분포의 차이를 통해 계산하는 방식이라는 점은 위 KS Test와 동일하지만, 각 원소의 분포를 비교하는것이

아닌, 구간별 분포를 비교한다는 부분에 있어 차이점이 있다. 그리고 PSI는 데이터 구간내에서 '기대빈도'와 '실제빈도'사이의 차이를 

비율로 표현하여 데이터 집단간의 분포차이를 수치화한다는 점이 특징이다.

아래 예시를 통해 확인해보자.

  • 표본 A : [1,2,2,3,4]
  • 표본 B : [2,3,3,4,5]

1단계) 데이터 구간 나누기 

예를들어 위 표본을 아래와 같이 세 구간으로 나눈다.

  • 구간1 : [1-2]
  • 구간2 : [3-4]
  • 구간3 : [5]

2단계) 구간별 데이터 비율 계산

표본 A와 표본B의 각 구간에서 데이터 비율을 계산한다.

  • 표본 A
    • 구간1 : 3/5 (원소 1,2,2가 여기 속한다)
    • 구간2 : 2/5 (원소 3,5가 여기 속한다)
    • 구간3 : 0/5 (해당하는 원소가 없다)
  • 표본 B
    • 구간1 : 1/5 (원소 2가 여기 속한다)
    • 구간2 : 3/5 (원소 3,3,4가 여기 속한다)
    • 구간3 : 1/5 (원소5가 여기 속한다)

3단계) PSI 계산

PSI는 다음 공식을 사용하여 계산된다.

위 예시 표본을 통해, PSI를 계산해보자.

 

  • 구간 1: (0.2-0.6) x ln(0.2/0.6)
  • 구간 2: (0.6-0.4) x ln(0.6/0.4)
  • 구간 3: (0.2-0) x ln(0.2/(0+

 

import numpy as np

# 샘플 데이터 생성
np.random.seed(0)
train_set = np.random.normal(0, 1, 1000)   # 초기 데이터셋 (정규 분포)
product_set = np.random.normal(0.1, 1.1, 1000)    # 새로운 데이터셋 (분포 약간 다르게)

# PSI 계산 함수 
def calculate_psi(train_set, product_set, buckets=10):
    # 구간 분할
    breakpoints = np.linspace(np.min([train_set.min(), product_set.min()]), np.max([train_set.max(), product_set.max()]), num=buckets + 1)
    train_set_counts = np.histogram(train_set, breakpoints)[0]
    product_set_counts = np.histogram(product_set, breakpoints)[0]

    # 분포 비율 계산
    train_set_ratios = train_set_counts / train_set_counts.sum()
    product_set_ratios = product_set_counts / product_set_counts.sum()

    # PSI 계산
    psi_value = np.sum((product_set_ratios - train_set_ratios) * np.log((product_set_ratios + 1e-10) / (train_set_ratios + 1e-10)))
    return psi_value

psi_value = calculate_psi(train_set, product_set)
print(f"PSI: {psi_value}")


[output] PSI: 0.10168885498870324

 

어느정도의 PSI 수치가 관찰되었을때, 주의가 필요하거나 데이터분포에 유의미한 변화가 있다고 가정할 수 있을지는

상황에 따라 경험적, 실험적인 판단이 필요하겠지만,

보통 0.1~0.2구간에서는 주의가 필요하며, 0.25이상의 차이가 관측될 경우 모델이나 데이터분포에 큰 변화가 있음을 의미하며

모델 또는 데이터 전략에 수정이 필요할 것으로 판단할 수 있다.

 

Visualization (시각화)

마지막으로, 데이터 분포의 변화를 시각화를 통해 직관적으로 파악하는 방법이다.

예를들어, 각 Feature의 최대값, 최소값, 평균값, 상관계수 등의 수치를 시간에 흐름에 따른 변화량을 관찰하는 방법이다.

가장 직관적이고 손쉽게 데이터의 변화 여부를 파악할 수 있다.

 

마치며

오늘은 여러 model drift의 원인 중 Data Drift 또는 Label Drift를 detection할 수 있는 여러 방법들을 

정리해보았다. 간단하게는 feature별 분포의 변화를 통해 데이터 변화를 관측할 수 있었고, 

PSI, KS Test를 통해 조금 더 객관적으로 기준데이터와 관찰데이터의 차이를 수치화할 수 있었다.

그리고, KS Test의 경우 표본 내 각 값들 사이의 분포를 비교한다면, PSI는 구간 내 데이터의 비교를 통해 차이를 관측하는 방법이므로,

목적과 상황에 따라 적절히 사용할 수 있도록 해야겠다.

다음에는 Concept Drift를 detction할 수 있는 검증방법에 대해 정리해보도록 하자.

 

 






Reference

1) Scipy document

https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.ks_2samp.html

 

scipy.stats.ks_2samp — SciPy v1.11.4 Manual

[1] Hodges, J.L. Jr., “The Significance Probability of the Smirnov Two-Sample Test,” Arkiv fiur Matematik, 3, No. 43 (1958), 469-86.

docs.scipy.org

2) Blog

https://www.fiddler.ai/blog/measuring-data-drift-population-stability-index

 

Measuring Data Drift: Population Stability Index | Fiddler AI Blog

Learn what Population Stability Index (PSI) measure is, its historical usage, and its connection to other mathematical drift measures such as KL divergence.

www.fiddler.ai

https://roytravel.tistory.com/349

 

[확률/통계] 누적분포함수 (CDF, Cumulative Distribution Function)

누적분포함수란 확률론에서 주어진 확률분포가 특정 값보다 작거나 같은 확률을 나타내는 함수이다. 이 특정 값이라는 것은 어떤 사건을 의미하므로 누적분포함수는 어떤 사건이 얼마나 많이/

roytravel.tistory.com

https://abluesnake.tistory.com/163

 

[모니터링] 2) 드리프트 감지 방법: KS 검정과 PSI

들어가며 지난 포스트에서 모델 드리프트의 개념과 원인에 대해 알아보았습니다. 시간이 지나면서 모델의 성능이 감소하는 현상을 모델 드리프트라고 하며, 모델 드리프트가 발생하는 주된 이

abluesnake.tistory.com