Ich denke, es gibt zwei Dinge, die dieses Thema verwirren:
- statistische vs. Signalverarbeitungsdefinition: Wie andere betont haben, normalisieren wir in der Statistik die Autokorrelation in [-1,1].
- partieller oder nicht partieller Mittelwert / Varianz: Wenn sich die Zeitreihen mit einer Verzögerung> 0 verschieben, ist ihre Überlappungsgröße immer <ursprüngliche Länge. Verwenden wir den Mittelwert und den Standard des Originals (nicht partiell) oder berechnen wir immer einen neuen Mittelwert und den Standard unter Verwendung der sich ständig ändernden Überlappung (teilweise), was einen Unterschied macht. (Es gibt wahrscheinlich einen formalen Begriff dafür, aber ich werde vorerst "teilweise" verwenden).
Ich habe 5 Funktionen erstellt, die die Autokorrelation eines 1d-Arrays mit partiellen und nicht partiellen Unterscheidungen berechnen. Einige verwenden Formeln aus Statistiken, andere Korrelate im Sinne der Signalverarbeitung, was auch über FFT erfolgen kann. Alle Ergebnisse sind jedoch Autokorrelationen in der Statistikdefinition , sodass sie veranschaulichen, wie sie miteinander verknüpft sind. Code unten:
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()
Hier ist die Ausgabezahl:
Wir sehen nicht alle 5 Linien, da sich 3 davon überlappen (lila). Die Überlappungen sind alle nicht partielle Autokorrelationen. Dies liegt daran, dass Berechnungen aus den Signalverarbeitungsverfahren ( np.correlate
FFT) nicht für jede Überlappung einen anderen Mittelwert / Standard berechnen.
Beachten Sie auch, dass das fft, no padding, non-partial
Ergebnis (rote Linie) anders ist, da die Zeitreihen vor der FFT nicht mit 0s aufgefüllt wurden, sodass es sich um eine kreisförmige FFT handelt. Ich kann nicht im Detail erklären, warum, das habe ich von anderswo gelernt.