Python) Data Drift 탐지 KS로 구현해보기

2022. 9. 3. 23:17분석 Python/구현 및 자료

728x90

다른 참고자료들을 보면서 이런 식으로 구현해볼 수 있지 않을까 해서 구현해봅니다.

한 가지 남은 이슈로는 이 코드 구현에서는 데이터의 히스토그램 정보를 저장하다 보니, 누적해서 계속 비교하는 것은 어떻게 해야 할지가 고민입니다.

이 부분 혹시 아이디어나 의견 있으면 댓글 부탁드려요!

 

DATA DRIFT란?

 

다양한 Drift 문제가 있는데 여기서는 Data Drift를 다루려고 합니다.

Data Drift란 간단히 말해서 시간이 변하면서, 데이터의 분포가 변하는 것을 의미합니다.


그래서 모델을 훈련하는 데 사용되는 데이터 세트와 실제 운영에서 받는 데이터를 모방하지 않을 때 발생합니다.

이것은 모델이 이상하게 작동하고 성능이 저하되기 시작하는 때입니다.

 

 

그래서 이러한 문제를 성능과 직결되는 문제를 가지고 있다 보니, 빠른 탐지를 통해 데이터 이슈를 발견하고, 

그 이슈를 해결하기 위해서 모델의 재학습을 하던지, 혹은 모델 운영을 중지할지와 같은 의사결정이 필요합니다.

 

이러한 개념을 보면서 한가지 의문을 가지고 있던 점은 데이터가 별로 없으면 상관이 없는데, 이벤트가 많아서 데이터가 엄청 많이 수집되는 곳에서 저걸 다 저장하면서 운영할 수 있을까라는 생각이 들었고, 그럴 때 어떻게 하면 좋을지에 대해서 생각해봤습니다.

 

구현

여기서는 간단하게 특정 1d의 분포를 이용해서 해보려고 합니다.

 

 

가정

한달 전에는 데이터가 평균이 5이면서, 편차가 1.5인 분포의 형태를 띠고 있었고, 

이번 달에는 어떤 특정 이벤트가 발생해서 데이터가 평균이 6이면서 편차가 1.0이 된 상황입니다.

 

과거에 이러한 데이터가 생성이 되었다고 합시다.

prev_data = np.random.normal(loc=5, scale=1.5, size=1000)

 

그러면 이 데이터를 활용해서  histogram 정보로 축약합니다.

여기서는 데이터를 10 등분해서 저장합니다.

아래 left,right,top,bottom은 시각화를 위해 필요합니다.

그럼 해당 데이터 1000개를 저장하지 않고 n과 bins 10 등분한 그리고 top, bottom, right, left 총 60개만 저장하는 형태로 유지할 수 있어서 이런 작업을 진행합니다.

nbins = 10
n, bins = np.histogram(prev_data, nbins)
left = bins[:-1]
right = bins[1:]
bottom = np.zeros(len(left))
top = bottom + n
prev_hist_info = dict(
    top=top,
    bottom=bottom,
    right=right,
    left=left,
    bins=bins,
)

 

그다음 현재 데이터를 수집했다 가정하고 다시 샘플링을 합니다.

after_data = np.random.normal(loc=6, scale=1.0, size=1000)

그리고 histogram 정보를 수집합니다.

nbins = 10
n, bins = np.histogram(after_data, nbins)
left = bins[:-1]
right = bins[1:]
bottom = np.zeros(len(left))
top = bottom + n
after_hist_info = dict(
    top=top,
    bottom=bottom,
    right=right,
    left=left,
    bins=bins,
)

 

이 두가지 데이터를 이용하여 시각화 및 ks 통계량을 계산할 수 있습니다.

bins를 이용해서 ks_2 samp 통계량을 계산할 수 있습니다.

 ks_test = ks_2samp(prev_hist_info["bins"], after_hist_info["bins"])
p_value = 0.05
if stat.pvalue < p_value:
    print("data is drifted")
else:
    print("data is not drifted")

 

 

이러한 것들을 함수 화해서 한 코드는 다음과 같습니다.

ks = DataDritDetectionKS(p_value=0.05, save_fig_path="./hist.png")

## past 1 month ago
prev_data = np.random.normal(loc=5, scale=1.5, size=1000)
prev_hist_info = ks.make_hist_info(prev_data, nbins=10)
## save information any format
PickleHandler.save_pickle("./past_1_month_hist_info.pkl", prev_hist_info)
del prev_hist_info
## current month
after_data = np.random.normal(loc=6, scale=1.0, size=1000)
after_hist_info = ks.make_hist_info(after_data, nbins=10)

prev_hist_info = PickleHandler.load_pickle("./past_1_month_hist_info.pkl")
print(ks.is_data_drift(prev_hist_info=prev_hist_info, after_hist_info=after_hist_info))
ks.visualize(prev_hist_info=prev_hist_info, after_hist_info=after_hist_info, show=False)

 

시각화

아래 결과처럼 p-value가 0.05보다 작지 않으므로, 귀무가설을 기각할 근거가 없게 됩니다.

즉, 정확한 해석은 아니지만, 직관적으로 말하면  두 분포가 같다로 판단할 수 있고, 아직까지는 data drift가 발생하지 않았다고 할 수 있습니다.

 

일부 수정된 버전 (22.09.12)

기존에는 train data와 히스토그램과 future data에 대해서 각각 히스토그램을 그려서 계산하는 방식이었다면,결국 핵심은 기존 train data의 히스토그램과 얼마나 차이가 있는 지를 표현하면 되기 때문에, 분포의 bins는 고정시키면서 future data를 과거 데이터의 맞추는 작업을 진행했다.관리하는 면에서나 시각적으로도 용이할 것 같아서 그렇게 진행하였다.아래처럼 bins를 세세하게 나누고 ks 통계량을 구하게 되면 서로 다른 분포로 판단할 수 있는 것은 동일하다.

CODE LINK

이쪽으로 추가적으로 아이디어나 기존 코드들이 있으면 활용해서 구현해서 정리해볼까 합니다.

https://github.com/sungreong/PyDataDriftDetection

 

GitHub - sungreong/PyDataDriftDetection: Python에서 Data Drift 탐지하기

Python에서 Data Drift 탐지하기. Contribute to sungreong/PyDataDriftDetection development by creating an account on GitHub.

github.com

Reference

 

https://www.analyticsvidhya.com/blog/2021/10/mlops-and-the-importance-of-data-drift-detection/

 

Data Drift Detection | Importance of Data Drift Detection

There are various ways to detect and handle data drift. Let us have a look at various methods using which we can detect data drift

www.analyticsvidhya.com

 

728x90