Processing math: 40%
본문 바로가기
Data Science/TimeSeries

Savitzky-Golay(사비츠키 골레이) 필터

by hyelog 2024. 12. 22.

1. Savitzky-Golay 필터란 무엇일까?

센서 데이터를 사용하면, 불필요한 변동 데이터가 들어오거나, 값이 튀는 경우가 많이 발생합니다.

따라서 좋은 데이터를 추출하기 위해 노이즈를 제거하는 작업은 매우 중요한데요. 이를 ‘평활화’하는 작업이라고 합니다.

예를 들어 동영상 촬영 시에 의도한 움직임과 미세한 손떨림을 구분해 손 떨림만 제거해야하는 경우 등이 평활화 작업이 필요하겠지요.

 

디테일을 살려야하는 작업에서 일반적인 평활화 필터인 이동 평균은 높게 튀는 값이나, 계단 모양의 변화를 무뎌지게 만드는 단점이 있습니다. 하지만 오늘 알아볼 Savitzky-Golay 필터(이하 SG필터)는 이러한 특성을 잘 보존한다는 장점이 있습니다.

이 필터는 디지털 평활화 다항식 필터 또는 최소제곱 평활화 필터라고도 불립니다.

 

SG 필터는 1964년 Abraham Savitzky(아브라함 사비츠키)와 Marcel J. E. Golay(마르셀 골레이)가 개발했습니다. 당시 그들은 화학 분석에서 사용되는 스펙트럼 데이터의 노이즈를 제거하면서도, 스펙트럼의 특징적인 피크들을 보존하는 방법이 필요해서 만들어 졌다고 하네요.

2. 직관적으로 이해하는 SG(Savitzky-Golay) 필터

출처 위키피디아

SG 필터는 다음과 같은 과정으로 동작합니다.

  1. 이동 윈도우 설정: 데이터의 각 지점을 중심으로 일정 크기의 윈도우를 설정합니다.
  2. 다항식 피팅: 윈도우 내의 데이터 포인트들을 저차원 다항식으로 근사합니다.
  3. 중심점 계산: 피팅된 다항식을 사용하여 윈도우의 중심점 값을 계산합니다.
  4. 윈도우 이동: 다음 데이터 포인트로 이동하여 과정을 반복합니다.

이동 윈도우(Moving Window)의 개념

이동 윈도우를 말로 설명해보면 창문을 옆으로 이동하면서 각 순간 보이는 부분에 대해 처리를 하는 거죠.

이것이 바로 '이동 윈도우'의 개념입니다.

 

예를 들어:

  • 창의 크기가 5라면, 한 번에 5개의 데이터 포인트를 봅니다
  • 이 창을 한 칸씩 이동하면서 전체 데이터를 살펴봅니다
  • 각 위치에서 창 안의 데이터를 가지고 계산을 수행합니다

다항식 피팅이란?

다항식 피팅은 일련의 점들을 가장 잘 표현하는 곡선을 찾는 과정입니다.

 

SG 필터에서는

1. 현재 창 안에 있는 데이터 포인트들을 봅니다

2. 이 점들을 가장 잘 표현하는 다항식을 찾습니다

p(t)=Mk=0aktk

3. 윈도우 내의 데이터 포인트 값 전체에 대해 n차 다항식을 최소제곱 피팅합니다.(윈도우 크기: 2n+1)

min

y_{filtered}(t) = \sum_{i=-n}^n c_i y_{i}

(여기서 c_i는 윈도우 크기와 다항식 차수에 의해 결정되는 고정된 계수입니다)

4.이 다항식에서 중앙점의 값을 계산합니다

5. 이 값을 필터링된 결과로 사용합니다

간단한 작동 방식 예시

  1. 윈도우 크기가 5인 윈도우 내의 데이터 값: [1.1, 0.9, 1.0, 1.2, 0.8]
  2. 2차 다항식으로 피팅
    1. 이 5개 점을 가장 잘 표현하는 2차 곡선을 찾음
  3. 중앙점(1.0)을 이 곡선 위의 값으로 대체
x = np.linspace(0,5)
y = [1.1, 0.9, 1.0, 1.2, 0.8]
window_length = 5
polyorder = 2
y_filtered = savgol_filter(y, window_length, polyorder)
y_filtered.round()

결과값

이 과정을 전체 데이터에 대해 반복하면서 노이즈가 제거된 신호를 얻게 됩니다.

3. 핵심 매개변수 이해하기

윈도우 크기의 역할

윈도우 크기는 한 번에 처리할 데이터 포인트의 개수를 결정합니다. 이는 필터의 평활화 정도에 직접적인 영향을 미칩니다.

같은 차수, 다른 윈도우

  • 큰 윈도우
    • 장점: 노이즈 제거 효과가 큼
    • 단점: 신호의 급격한 변화가 무뎌질 수 있음
    • 적합: 천천히 변하는 신호, 노이즈가 많은 경우
  • 작은 윈도우
    • 장점: 신호의 급격한 변화를 잘 보존
    • 단점: 노이즈 제거 효과가 작음
    • 적합: 빠르게 변하는 신호, 노이즈가 적은 경우

다항식 차수(Polynomial Order)의 의미

다항식 차수는 피팅할 곡선의 복잡도를 결정합니다. 마치 그림을 그릴 때 사용할 곡선의 유연성을 정하는 것과 비슷합니다.

같은 윈도우, 다른 차수

  • 높은 차수
    • 복잡한 변화를 잘 표현할 수 있음
    • 노이즈에 더 민감할 수 있음
    • 주로 3-4차 이상
  • 낮은 차수
    • 단순한 변화만 표현 가능
    • 더 강한 평활화 효과
    • 주로 2-3차

매개변수 선택 가이드

(선택 가이드는 추천이어라! 최적의 매개변수는 데이터의 특성에 따라 결정해야 합니다!!)

  1. 첫 시도 추천값
    • 윈도우 크기: 데이터의 주요 특징의 길이보다 작게
    • 다항식 차수: 2-3차에서 시작
  2. 미세 조정
    • 노이즈가 더 남아있다면 → 윈도우 크기 증가
    • 중요한 특징이 사라진다면 → 윈도우 크기 감소
    • 곡선이 데이터를 잘 따르지 못한다면 → 차수 증가
    • 오버피팅이 발생한다면 → 차수 감소
  3. 주의사항
    • 윈도우 크기는 반드시 홀수여야 함
    • 차수는 윈도우 크기보다 작아야 함
    • 윈도우 크기가 너무 크면 계산 시간이 증가

모드 별 특징

아래 그림과 같이 모드별로 경계값이 조금 다르게 처리되는데요.

(이는 Python의 scipy 라이브러리의 savgol_filter를 사용할 시의 mode를 의미합니다)

모드별로 경계가 다르게 처리된 것을 볼 수 있다.

  1. 'mirror' 모드
    • 경계 부근의 데이터를 거울처럼 반사하여 확장
    • 데이터의 연속성을 비교적 잘 보존
    • 급격한 변화가 없는 신호에 적합
    • 예: [1,2,3] → [3,2,1, 1,2,3, 3,2,1]
  2. 'constant' 모드
    • 경계 값을 그대로 확장
    • 가장 단순한 방식
    • 경계에서 평평한 구간이 생김
    • 예: [1,2,3] → [1,1,1, 1,2,3, 3,3,3]
  3. 'nearest' 모드
    • 가장 가까운 값으로 확장
    • 'constant'와 비슷하지만 경계값 사용
    • 불연속점이 생길 수 있음
    • 예: [1,2,3] → [1,1,1, 1,2,3, 3,3,3]
  4. 'wrap' 모드
    • 데이터를 순환적으로 반복
    • 주기적인 신호에 적합
    • 시작과 끝이 비슷한 값을 가질 때 유용
    • 예: [1,2,3] → [2,3,1, 1,2,3, 1,2,3]
  5. 'interp' 모드
    • 경계를 보간하여 확장
    • 부드러운 전환을 제공
    • 연속적인 데이터에 적합
    • 다항식 외삽을 사용

모드 선택 가이드

(선택 가이드는 추천이어라! 최적의 모드는 데이터의 특성에 따라 결정해야 합니다22)

  1. 일반적인 경우 → 'mirror' 모드 추천
  2. 주기적인 신호 → 'wrap' 모드 추천
  3. 부드러운 전환이 필요할 때 → 'interp' 모드 추천
  4. 경계값 보존이 중요할 때 → 'nearest' 또는 'constant' 모드 추천

4. Python으로 구현해보기

Python의 scipy 라이브러리를 사용하면 쉽게 SG 필터를 적용할 수 있습니다.

이 예시는 위 윈도우와 다항식 매개변수 비교시 사용한 plot을 그렸던 코드입니다.

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import savgol_filter

# 데이터 생성
np.random.seed(42)  # 재현성을 위한 시드 설정
x = np.linspace(0, 10, 1000) # 100개의 데이터 포인트
# 복잡한 신호 생성 (여러 주파수의 사인파 + 노이즈)
y = (np.sin(x) + 0.5*np.sin(2*x) + 0.2*np.sin(5*x) + 
     np.random.normal(0, 0.2, 1000))

# 다양한 매개변수로 SG 필터 적용
window_lengths = [11, 51, 151]
poly_orders = [2, 3, 4]

# 서브플롯 생성
fig, axes = plt.subplots(len(window_lengths), len(poly_orders), 
                        figsize=(15, 15))
fig.suptitle('Savitzky-Golay 필터 매개변수 비교', fontsize=16)

for i, window_length in enumerate(window_lengths):
    for j, poly_order in enumerate(poly_orders):
        # SG 필터 적용
        y_filtered = savgol_filter(y, window_length, poly_order)
        
        # 결과 플로팅
        axes[i,j].plot(x, y, 'gray', alpha=0.5, label='원본 신호')
        axes[i,j].plot(x, y_filtered, 'r', label='필터링된 신호')
        axes[i,j].set_title(f'Window: {window_length}, Order: {poly_order}')
        axes[i,j].legend()
        axes[i,j].grid(True)
        

plt.tight_layout()
plt.show()

결론

업무에서 평탄화 필터를 자주 쓰게 되어 정리해 보았는데요.

센서 데이터 이외에도 다양한 분야에서 많이 쓰이고 있는 필터입니다. 금융데이터 등이 있다고 하네요!

물론 여전히 데이터의 시작과 끝에 왜곡이 존재하는 한계가 있지만, 매개변수를 잘 찾아준다면 아주 효과적으로 동작하는 친구랍니다.

참고

 

댓글