데이터 사이언스를 위한 푸리에 변환
시계열을 분석하기 위해 쓰이는 푸리에 변환에 대해 알아보고 Python으로 간단하게 구현해보겠습니다.
전력 소비량과 같은 시계열은 여러 요인들에 의해 영향을 받고 있지만, 요인들에 대한 정보가 없을 때는 분석하기가 쉽지 않습니다. 시계열은 여러 요인들의 혼합된 결과값이라고 할 때, 주파수 분해를 통해 의미있는 결과를 도출할 수 있습니다. 주파수 분해라는 것은 시계열에서 주기가 서로 다른 파동들을 분해하는 것입니다. 대표적인 주파수 분해 방법이 Fourier Transform(푸리에 변환)입니다.
Fourier Transform(푸리에 변환)
푸리에 변환은 아래와 같이 시간의 영역에 존재하는 시계열(검정)을 주파수(빨강) 영역으로 변환시킵니다. 푸리에 변환을 통해 시계열에 존재하는주파수를 찾을 수 있으며, 이를 통해 시계열을 구성하는 서로 다른 주기를 가진 파동(파랑)을 분해할 수 있습니다. 분해된 파동은 서로 다른 주파수를 가지는 정현파(사인파)입니다.
이제 scipy에서 제공하는 fast fourier transform(fft)를 이용하여 간단히 실습해보겠습니다.
실습에 필요한 matplotlib, numpy, scipy를 불러옵니다.
구간[0,1]에서 N개를 등간격으로 샘플링하여 xa를 생성합니다. 0이상 1이하의 범위에서 총 1000개의 값이 만들어졌습니다.
x를 대입하고 주기를 각각 1/10, 1/20, 1/50/ 1/70으로 하여 주파수가 10Hz, 20Hz, 50Hz, 70Hz인 정현파값을 생성합니다.
y1, y2, y3, y4를 그래프로 나타낸면 아래와 같습니다.
y1, y2, y3, y4를 모두 더하여 새로운 시계열을 생성합니다. 따라서 시계열은 10Hz, 20Hz, 50Hz, 70Hz의 성분을 모두 포함하는 시계열입니다.
fftfreq함수를 이용하여 주파수 스펙트럼을 생성합니다. 주파수 스펙트럼은 탐색할 주파수들의 후보군으로 생각할 수 있습니다. 이번 실습에서 frequency는 1000개의 주파수로 구성된 array이고 다음과 같습니다.
[0, 1, 2, …, 499, -500, -499, … ,-2, -1]
주파수의 음수 영역을 제외하기 위해 500개 (N//2)만 취합니다.
fft함수로 amplitude (푸리에 변환 계수; 크기)를 계산합니다. amplitude는 주파수의 강도로 이해할 수 있습니다. amplitude는 샘플 개수(N)에 비례하기 때문에 정규화하기 위해서 N으로 나누어줍니다.
시계열에서 분해된 주파수를 그래프로 나타내면 아래와 같습니다.
분해된 주파수를 통해 각각의 주파수를 가진 정현파를 재현하면 시계열을 구성하는 서로 다른 주기의 파동을 알아 낼 수 있습니다. 위의 그래프를 보면 푸리에 변환을 통해 시계열에서 10Hz, 20Hz, 50Hz, 70Hz의 주파수를 추출했습니다.
이번에는 같은 주파수로 구성된 다른 시계열을 구현하면서 푸리에 변환의 특징을 알아보겠습니다.
이번에 생성한 시계열은 서로 다른 주파수를 가진 정현파를 시간순서대로 결합했습니다. 좀 전의 시계열과 분명히 다른 시계열임에도 불구하고, 추출되는 주파수는 같습니다. 아래 그림을 통해 알아볼 수 있습니다.
위에서 실행한 두 번의 푸리에 변환을 통해 푸리에 변환은 시계열에 포함된 주파수를 분해하는 것은 가능하지만, 그 주파수가 어느 시간대에 존재하는 지는 알 수 없다는 것을 알 수 있습니다. 이를, 주파수 분해능은 높지만 시간 분해능은 낮다고 말합니다. 따라서, 푸리에 변환을 통해 시계열을 분해할 때는 이 점을 주의해야합니다.
푸리에 변환이 시간 분해능이 낮기 때문에, 이를 보완하는 short time fourier transform과 wavelet transform 같은 다른 주파수 분해 방법도 있습니다. Wavelet transform은 다음 시간에 알아보겠습니다.