Je pense qu'il y a 2 choses qui ajoutent de la confusion à ce sujet:
- définition statistique vs traitement du signal: comme d'autres l'ont souligné, en statistique, nous normalisons l'autocorrélation en [-1,1].
- moyenne / variance partielle vs non partielle: lorsque les séries temporelles se décalent avec un décalage> 0, leur taille de chevauchement sera toujours <longueur d'origine. Utilisons-nous la moyenne et std de l'original (non partiel), ou calculons-nous toujours une nouvelle moyenne et std en utilisant le chevauchement en constante évolution (partiel) fait une différence. (Il y a probablement un terme formel pour cela, mais je vais utiliser "partiel" pour l'instant).
J'ai créé 5 fonctions qui calculent l'auto-corrélation d'un tableau 1d, avec des distinctions partielles et non partielles. Certains utilisent la formule des statistiques, d'autres utilisent la corrélation dans le sens du traitement du signal, ce qui peut également être fait via FFT. Mais tous les résultats sont des auto-corrélations dans la définition des statistiques , ils illustrent donc comment ils sont liés les uns aux autres. Code ci-dessous:
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()
Voici la figure de sortie:
Nous ne voyons pas les 5 lignes car 3 d'entre elles se chevauchent (en violet). Les chevauchements sont tous des auto-corrélations non partielles. En effet, les calculs à partir des méthodes de traitement du signal (np.correlate
, FFT) ne calculent pas une moyenne / std différente pour chaque chevauchement.
Notez également que le résultat fft, no padding, non-partial
(ligne rouge) est différent, car il n'a pas rempli la série temporelle de 0 avant de faire la FFT, donc c'est une FFT circulaire. Je ne peux pas expliquer en détail pourquoi, c'est ce que j'ai appris d'ailleurs.