web-dev-qa-db-fra.com

Estimer l'autocorrélation à l'aide de Python

Je souhaite effectuer une autocorrélation sur le signal indiqué ci-dessous. Le temps entre deux points consécutifs est de 2,5 ms (ou un taux de répétition de 400 Hz).

enter image description here

Voici l'équation d'estimation de l'auto-corrélation que je voudrais utiliser (extrait de http://en.wikipedia.org/wiki/Autocorrelation , section Estimation):

enter image description here

Quelle est la méthode la plus simple pour trouver l'autocorrélation estimée de mes données en python? Existe-t-il quelque chose de similaire à numpy.correlate que je puisse utiliser? 

Ou devrais-je simplement calculer la moyenne et la variance?


Modifier:

Avec l’aide de unutbu , j’ai écrit:

from numpy import *
import numpy as N
import pylab as P

fn = 'data.txt'
x = loadtxt(fn,unpack=True,usecols=[1])
time = loadtxt(fn,unpack=True,usecols=[0]) 

def estimated_autocorrelation(x):
    n = len(x)
    variance = x.var()
    x = x-x.mean()
    r = N.correlate(x, x, mode = 'full')[-n:]
    #assert N.allclose(r, N.array([(x[:n-k]*x[-(n-k):]).sum() for k in range(n)]))
    result = r/(variance*(N.arange(n, 0, -1)))
    return result

P.plot(time,estimated_autocorrelation(x))
P.xlabel('time (s)')
P.ylabel('autocorrelation')
P.show()
28
8765674

Je ne pense pas qu'il existe une fonction NumPy pour ce calcul particulier. Voici comment je l'écrirais:

def estimated_autocorrelation(x):
    """
    http://stackoverflow.com/q/14297012/190597
    http://en.wikipedia.org/wiki/Autocorrelation#Estimation
    """
    n = len(x)
    variance = x.var()
    x = x-x.mean()
    r = np.correlate(x, x, mode = 'full')[-n:]
    assert np.allclose(r, np.array([(x[:n-k]*x[-(n-k):]).sum() for k in range(n)]))
    result = r/(variance*(np.arange(n, 0, -1)))
    return result

L'instruction assert est là pour vérifier le calcul et documenter son intention. 

Lorsque vous êtes sûr que cette fonction se comporte comme prévu, vous pouvez commenter l'instruction assert ou exécuter votre script avec python -O. (L’indicateur -O indique à Python d’ignorer les instructions d’assertion.)

29
unutbu

J'ai pris une partie du code de la fonction autocorrelation_plot () de pandas. J'ai vérifié les réponses avec R et les valeurs correspondent exactement.

import numpy
def acf(series):
    n = len(series)
    data = numpy.asarray(series)
    mean = numpy.mean(data)
    c0 = numpy.sum((data - mean) ** 2) / float(n)

    def r(h):
        acf_lag = ((data[:n - h] - mean) * (data[h:] - mean)).sum() / float(n) / c0
        return round(acf_lag, 3)
    x = numpy.arange(n) # Avoiding lag 0 calculation
    acf_coeffs = map(r, x)
    return acf_coeffs
16
Kathirmani Sukumar

Le package statsmodels ajoute une fonction d'autocorrélation qui utilise en interne np.correlate (selon la documentation statsmodels).

Voir: http://statsmodels.sourceforge.net/stable/generated/statsmodels.tsa.stattools.acf.html#statsmodels.tsa.stattools.acf

11
hamogu

La méthode que j'ai écrite depuis ma dernière édition est maintenant plus rapide que même scipy.statstools.acf avec fft=True jusqu'à ce que la taille de l'échantillon soit très grande.

Analyse d'erreur Si vous voulez ajuster les biais et obtenir des estimations d'erreur très précises: Regardez mon code ici qui implémente cet article par Ulli Wolff ( ou original de UW dans Matlab )

Fonctions testées

  • a = correlatedData(n=10000) provient d'une routine trouvée ici
  • gamma() vient du même endroit que correlated_data() 
  • acorr() est ma fonction ci-dessous
  • estimated_autocorrelation se trouve dans une autre réponse
  • acf() est de from statsmodels.tsa.stattools import acf

Les horaires

%timeit a0, junk, junk = gamma(a, f=0)                            # puwr.py
%timeit a1 = [acorr(a, m, i) for i in range(l)]                   # my own
%timeit a2 = acf(a)                                               # statstools
%timeit a3 = estimated_autocorrelation(a)                         # numpy
%timeit a4 = acf(a, fft=True)                                     # stats FFT

## -- End pasted text --
100 loops, best of 3: 7.18 ms per loop
100 loops, best of 3: 2.15 ms per loop
10 loops, best of 3: 88.3 ms per loop
10 loops, best of 3: 87.6 ms per loop
100 loops, best of 3: 3.33 ms per loop

Edit ... J'ai vérifié à nouveau en conservant l=40 et en remplaçant n=10000 par n=200000 exemples, les méthodes FFT commencent à avoir un peu de traction et la mise en œuvre de statsmodelsfft le contourne ... (l'ordre est le même)

## -- End pasted text --
10 loops, best of 3: 86.2 ms per loop
10 loops, best of 3: 69.5 ms per loop
1 loops, best of 3: 16.2 s per loop
1 loops, best of 3: 16.3 s per loop
10 loops, best of 3: 52.3 ms per loop

Edit 2: J'ai changé ma routine et re-testé contre la FFT pour n=10000 et n=20000

a = correlatedData(n=200000); b=correlatedData(n=10000)
m = a.mean(); rng = np.arange(40); mb = b.mean()
%timeit a1 = map(lambda t:acorr(a, m, t), rng)
%timeit a1 = map(lambda t:acorr.acorr(b, mb, t), rng)
%timeit a4 = acf(a, fft=True)
%timeit a4 = acf(b, fft=True)

10 loops, best of 3: 73.3 ms per loop   # acorr below
100 loops, best of 3: 2.37 ms per loop  # acorr below
10 loops, best of 3: 79.2 ms per loop   # statstools with FFT
100 loops, best of 3: 2.69 ms per loop # statstools with FFT

La mise en oeuvre

def acorr(op_samples, mean, separation, norm = 1):
    """autocorrelation of a measured operator with optional normalisation
    the autocorrelation is measured over the 0th axis

    Required Inputs
        op_samples  :: np.ndarray :: the operator samples
        mean        :: float :: the mean of the operator
        separation  :: int :: the separation between HMC steps
        norm        :: float :: the autocorrelation with separation=0
    """
    return ((op_samples[:op_samples.size-separation] - mean)*(op_samples[separation:]- mean)).ravel().mean() / norm

4x accélération peut être obtenue ci-dessous. Veillez à ne transmettre que op_samples=a.copy() car cela modifiera le tableau a de a-=mean sinon:

op_samples -= mean
return (op_samples[:op_samples.size-separation]*op_samples[separation:]).ravel().mean() / norm

Verification sanitaire

 enter image description here

Exemple d'analyse d'erreur

Ceci est un peu en dehors de la portée mais je ne peux pas être dérangé pour refaire la figure sans le temps d'autocorrélation intégré ou le calcul de la fenêtre d'intégration. Les autocorrélations avec des erreurs sont claires dans le graphique du bas  enter image description here

7
Alexander McFarlane

J'ai trouvé que cela a eu les résultats attendus avec juste un léger changement:

def estimated_autocorrelation(x):
    n = len(x)
    variance = x.var()
    x = x-x.mean()
    r = N.correlate(x, x, mode = 'full')
    result = r/(variance*n)
    return result

Test par rapport aux résultats d'autocorrélation d'Excel.

1
Corin Dawson