Menurut saya ada 2 hal yang menambah kebingungan pada topik ini:
- statistik vs definisi pemrosesan sinyal: seperti yang ditunjukkan orang lain, dalam statistik kami menormalkan korelasi otomatis menjadi [-1,1].
- mean / varians parsial vs non-parsial: ketika deretan waktu bergeser dengan kelambatan> 0, ukuran tumpang tindihnya akan selalu <panjang aslinya. Apakah kita menggunakan mean dan std dari yang asli (non-parsial), atau selalu menghitung mean dan std baru menggunakan tumpang tindih yang terus berubah (parsial) membuat perbedaan. (Mungkin ada istilah formal untuk ini, tapi saya akan menggunakan "parsial" untuk saat ini).
Saya telah membuat 5 fungsi yang menghitung korelasi otomatis dari array 1d, dengan perbedaan parsial vs non-parsial. Beberapa menggunakan rumus dari statistik, beberapa menggunakan korelasi dalam pengertian pemrosesan sinyal, yang juga dapat dilakukan melalui FFT. Tetapi semua hasil merupakan korelasi otomatis dalam definisi statistik , jadi hasil tersebut menggambarkan bagaimana mereka ditautkan satu sama lain. Kode di bawah ini:
import numpy
import matplotlib.pyplot as plt
def autocorr1(x,lags):
'''numpy.corrcoef, partial'''
corr=[1. if l==0 else numpy.corrcoef(x[l:],x[:-l])[0][1] for l in lags]
return numpy.array(corr)
def autocorr2(x,lags):
'''manualy compute, non partial'''
mean=numpy.mean(x)
var=numpy.var(x)
xp=x-mean
corr=[1. if l==0 else numpy.sum(xp[l:]*xp[:-l])/len(x)/var for l in lags]
return numpy.array(corr)
def autocorr3(x,lags):
'''fft, pad 0s, non partial'''
n=len(x)
# pad 0s to 2n-1
ext_size=2*n-1
# nearest power of 2
fsize=2**numpy.ceil(numpy.log2(ext_size)).astype('int')
xp=x-numpy.mean(x)
var=numpy.var(x)
# do fft and ifft
cf=numpy.fft.fft(xp,fsize)
sf=cf.conjugate()*cf
corr=numpy.fft.ifft(sf).real
corr=corr/var/n
return corr[:len(lags)]
def autocorr4(x,lags):
'''fft, don't pad 0s, non partial'''
mean=x.mean()
var=numpy.var(x)
xp=x-mean
cf=numpy.fft.fft(xp)
sf=cf.conjugate()*cf
corr=numpy.fft.ifft(sf).real/var/len(x)
return corr[:len(lags)]
def autocorr5(x,lags):
'''numpy.correlate, non partial'''
mean=x.mean()
var=numpy.var(x)
xp=x-mean
corr=numpy.correlate(xp,xp,'full')[len(x)-1:]/var/len(x)
return corr[:len(lags)]
if __name__=='__main__':
y=[28,28,26,19,16,24,26,24,24,29,29,27,31,26,38,23,13,14,28,19,19,\
17,22,2,4,5,7,8,14,14,23]
y=numpy.array(y).astype('float')
lags=range(15)
fig,ax=plt.subplots()
for funcii, labelii in zip([autocorr1, autocorr2, autocorr3, autocorr4,
autocorr5], ['np.corrcoef, partial', 'manual, non-partial',
'fft, pad 0s, non-partial', 'fft, no padding, non-partial',
'np.correlate, non-partial']):
cii=funcii(y,lags)
print(labelii)
print(cii)
ax.plot(lags,cii,label=labelii)
ax.set_xlabel('lag')
ax.set_ylabel('correlation coefficient')
ax.legend()
plt.show()
Berikut adalah gambar keluarannya:
Kami tidak melihat semua 5 baris karena 3 di antaranya tumpang tindih (di ungu). Semua tumpang tindih adalah korelasi otomatis non-parsial. Ini karena perhitungan dari metode pemrosesan sinyal ( np.correlate
, FFT) tidak menghitung mean / std yang berbeda untuk setiap tumpang tindih.
Perhatikan juga bahwa hasil fft, no padding, non-partial
(garis merah) berbeda, karena tidak mengisi deretan waktu dengan 0 sebelum melakukan FFT, jadi FFT melingkar. Saya tidak bisa menjelaskan secara detail mengapa, itulah yang saya pelajari dari tempat lain.