web-dev-qa-db-fra.com

Quelle est la différence entre les pandas ACF et les statsmodel ACF?

Je calcule la fonction d'autocorrélation pour les rendements d'une action. Pour ce faire, j'ai testé deux fonctions, la fonction autocorr intégrée aux Pandas et la fonction acf fournie par statsmodels.tsa. Ceci est fait dans le MWE suivant:

import pandas as pd
from pandas_datareader import data
import matplotlib.pyplot as plt
import datetime
from dateutil.relativedelta import relativedelta
from statsmodels.tsa.stattools import acf, pacf

ticker = 'AAPL'
time_ago = datetime.datetime.today().date() - relativedelta(months = 6)

ticker_data = data.get_data_yahoo(ticker, time_ago)['Adj Close'].pct_change().dropna()
ticker_data_len = len(ticker_data)

ticker_data_acf_1 =  acf(ticker_data)[1:32]
ticker_data_acf_2 = [ticker_data.autocorr(i) for i in range(1,32)]

test_df = pd.DataFrame([ticker_data_acf_1, ticker_data_acf_2]).T
test_df.columns = ['Pandas Autocorr', 'Statsmodels Autocorr']
test_df.index += 1
test_df.plot(kind='bar')

Ce que j'ai remarqué, c'est que les valeurs prédites n'étaient pas identiques:

 enter image description here

Qu'est-ce qui explique cette différence et quelles valeurs doivent être utilisées?

21
BML91

La différence entre les versions Pandas et Statsmodels réside dans la soustraction moyenne et la division normalisation/variance:

  • autocorr ne fait rien d'autre que transmettre les sous-séries de la série d'origine à np.corrcoef. Dans cette méthode, la moyenne et la variance de l'échantillon de ces sous-séries sont utilisées pour déterminer le coefficient de corrélation
  • acf, au contraire, utilise la moyenne et la variance d'échantillon de la série globale pour déterminer le coefficient de corrélation.

Les différences peuvent être plus petites pour les séries chronologiques plus longues, mais assez grandes pour les plus courtes.

Par rapport à Matlab, la fonction Pandas autocorr correspond probablement à la réalisation de Matlabs xcorr (corrélation croisée) avec la série (décalée) elle-même, à la place de la variable autocorr de Matlab, qui calcule l’exemple d’autocorrélation (deviner à partir des documents; je ne peux pas le valider car je ne peux pas le valider). pas d'accès à Matlab). 

Voir ce MWE pour clarification:

import numpy as np
import pandas as pd
from statsmodels.tsa.stattools import acf
import matplotlib.pyplot as plt
plt.style.use("seaborn-colorblind")

def autocorr_by_hand(x, lag):
    # Slice the relevant subseries based on the lag
    y1 = x[:(len(x)-lag)]
    y2 = x[lag:]
    # Subtract the subseries means
    sum_product = np.sum((y1-np.mean(y1))*(y2-np.mean(y2)))
    # Normalize with the subseries stds
    return sum_product / ((len(x) - lag) * np.std(y1) * np.std(y2))

def acf_by_hand(x, lag):
    # Slice the relevant subseries based on the lag
    y1 = x[:(len(x)-lag)]
    y2 = x[lag:]
    # Subtract the mean of the whole series x to calculate Cov
    sum_product = np.sum((y1-np.mean(x))*(y2-np.mean(x)))
    # Normalize with var of whole series
    return sum_product / ((len(x) - lag) * np.var(x))

x = np.linspace(0,100,101)

results = {}
nlags=10
results["acf_by_hand"] = [acf_by_hand(x, lag) for lag in range(nlags)]
results["autocorr_by_hand"] = [autocorr_by_hand(x, lag) for lag in range(nlags)]
results["autocorr"] = [pd.Series(x).autocorr(lag) for lag in range(nlags)]
results["acf"] = acf(x, unbiased=True, nlags=nlags-1)

pd.DataFrame(results).plot(kind="bar", figsize=(10,5), grid=True)
plt.xlabel("lag")
plt.ylim([-1.2, 1.2])
plt.ylabel("value")
plt.show()

 enter image description here

Statsmodels utilise np.correlate pour l'optimiser, mais c'est comme ça que ça fonctionne.

16
nikhase

Comme suggéré dans les commentaires, le problème peut être réduit, mais pas complètement résolu, en fournissant unbiased=True à la fonction statsmodels. En utilisant une entrée aléatoire:

import statistics

import numpy as np
import pandas as pd
from statsmodels.tsa.stattools import acf

DATA_LEN = 100
N_TESTS = 100
N_LAGS = 32

def test(unbiased):
  data = pd.Series(np.random.random(DATA_LEN))
  data_acf_1 = acf(data, unbiased=unbiased, nlags=N_LAGS)
  data_acf_2 = [data.autocorr(i) for i in range(N_LAGS+1)]
  # return difference between results
  return sum(abs(data_acf_1 - data_acf_2))

for value in (False, True):
  diffs = [test(value) for _ in range(N_TESTS)]
  print(value, statistics.mean(diffs))

Sortie:

False 0.464562410987
True 0.0820847168593
0
Marein