使用周期图来检测时间序列的季节性

时间:2019-03-26 13:59:29

标签: python fft data-mining forecasting ifft

我正在使用周期图绘制捕获时间序列的季节性,我想使用前十个频率分量来创建季节性时间序列,到目前为止,我绘制了周期图:

data=elec_price[:48*365]
from scipy.signal import periodogram
f, Pxx_den = periodogram(data)

数据是一年的价格子集,间隔30分钟 ,并按振幅对它进行排序后,从Fourier_coefficients列表中捕获了前十个频率分量

fourier_coefficients=Pxx_den.tolist()
fourier_coefficients=pd.DataFrame(fourier_coefficients,columns=['amplitude'])

具有最高振幅的最高频率是: 365,2,730,22,52,5,729,8 ,接下来我需要使用这些最高频率分量来获取时间序列的季节性,我生成了每个频率分量的正弦波,并将它们加在一起绘制时间序列,以为我不确定这是否是正确的方法,因为我记得频率分量应该有一个虚部,但我无法从周期图数据中找到它,其次,我仅假设这些分量中的每一个都是正弦波。

sin_waves=fourier_coefficients.drop(columns=['frequency coneficient','amplitude']).copy()
sin_waves[' sin_wave_1']=0
sin_waves[' sin_wave_2']=0
sin_waves[' sin_wave_3']=0
sin_waves[' sin_wave_4']=0
sin_waves[' sin_wave_5']=0
sin_waves[' sin_wave_6']=0
sin_waves[' sin_wave_7']=0
sin_waves[' sin_wave_8']=0
for i in range(8761):
    sin_waves[' sin_wave_1'][i]= fourier_coefficients['amplitude'][365]*math.sin(math.pi*i*365/8761)
    sin_waves[' sin_wave_2'][i]= fourier_coefficients['amplitude'][2]*math.sin(math.pi*i*2/8761)
    sin_waves[' sin_wave_3'][i]= fourier_coefficients['amplitude'][730]*math.sin(math.pi*i*730/8761)
    sin_waves[' sin_wave_4'][i]= fourier_coefficients['amplitude'][22]*math.sin(math.pi*i*22/8761)
    sin_waves[' sin_wave_5'][i]= fourier_coefficients['amplitude'][52]*math.sin(math.pi*i*52/8761)
    sin_waves[' sin_wave_6'][i]= fourier_coefficients['amplitude'][5]*math.sin(math.pi*i*5/8761)
    sin_waves[' sin_wave_7'][i]= fourier_coefficients['amplitude'][729]*math.sin(math.pi*i*729/8761)
    sin_waves[' sin_wave_8'][i]= fourier_coefficients['amplitude'][8]*math.sin(math.pi*i*8/8761)
sin_waves['accumulated_sin_wave']=(sin_waves[' sin_wave_1']+sin_waves[' sin_wave_2']
                + sin_waves[' sin_wave_3']+sin_waves[' sin_wave_4']+sin_waves[' sin_wave_5']+
                sin_waves[' sin_wave_6']+sin_waves[' sin_wave_7']+sin_waves[' sin_wave_8'])

8761是数据中的样本数。
然后,我绘制了sinaves['accumulated_sin_wave']

以下是第一年的季节性成分图:

here

因此,我想知道应该怎么做,而不是仅仅绘制这些正弦波来捕获最高频率的真实分量。

1 个答案:

答案 0 :(得分:0)

对我来说,更好,更轻松的方法就是使用FFT滤波IFFT模型,它看起来很简单,首先我使用以下方法为数据绘制FFt:

package main

import (
    "fmt"
    "github.com/bobby96333/goSqlHelper"
)

func main(){
    fmt.Println("hello")
    conn,err :=goSqlHelper.MysqlOpen("user:password@tcp(127.0.0.1:3306)/dbname")
    checkErr(err)
    row,err := conn.QueryRow("select * from table where col1 = ? and  col2 = ?","123","abc")
    checkErr(err)
    if *row==nil {
        fmt.Println("no found row")
    }else{
        fmt.Printf("%+v",row)
    }
}

func checkErr(err error){
    if err!=nil {
        panic(err)
    }
}

此后,我按幅度对功率列表进行了排序,并使用了前10个频率,这些频率对于我的数据是: 0,365,17155,1,17519,11,17509,366,17154,2,17518 请注意,0是数据中的DC分量,因此您可以使用或不使用它,具体取决于您是否要抵消季节性变化。 另外,请注意,这些频率中的每一个都是偶数,每个偶数都是彼此的镜像,因为FFT是一个绘图,其中每个频率分量及其负频率具有相同的功率。 选择了我的前5个频率后,我过滤了FFT_filtered列表:

one_year_values=48*365
data=elec_price[:one_year_values]
from numpy.fft import fft, fftfreq, ifft

n=len(data)
freqs=fftfreq(n)
mask = freqs>0


fft_values=fft(data)
fft_list=np.copy(fft_values).tolist()
fft_filtered=np.copy(fft_list).tolist() # copying from the original fft list in order to filter it

power= 2*(np.abs(fft_values/one_year_values))**2 # calculating the power make sit easy to compare between frequency components, because they are complex numbers, and the power of them gets the absolute values of them.
power=power.tolist()

然后,我使用IFFT验证FFt,以使用前5个频率获得数据图:

tuple(fft_filtered)
for i in range(len(fft_filtered)):
    fft_filtered[i]=0
for i in (0
,365
,17155
,1
,17519
,11
,17509
,366
,17154
,2
,17518):
    fft_filtered[i]=fft_list[i]

,这是反向列表的图解: 1 year seasonality using top 5 frequencies