2016-03-16 15 views
12

Sto calcolando la funzione di autocorrelazione per i rendimenti di un magazzino. Per fare ciò ho testato due funzioni, la funzione autocorr integrata in Pandas e la funzione acf fornita da statsmodels.tsa. Questo viene fatto nel seguente MWE:Qual è la differenza tra pandas ACF e statsmodel ACF?

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') 

Quello che ho notato è stato i valori avevano previsto non erano identici:

enter image description here

Che cosa rappresenta questa differenza, e quali valori dovrebbero essere utilizzati?

+2

Guardando i documenti i ritardi di default sono '1' per la versione pandas e' 40' per statsmodel – EdChum

+0

Prova 'transparent = True' come opzione per la versione statsmodels. – user333700

+0

Hai invertito le etichette nella trama, penso che 'imparziali = True' dovrebbe rendere più grandi i coefficienti di autocorrelazione. – user333700

risposta

4

La differenza tra la versione Pandas e Statsmodels trovano nel mezzo sottrazione e normalizzazione/varianza divisione:

  • autocorr non fa altro di passare sottoserie della serie originale a np.corrcoef. All'interno di questo metodo, la media campionaria e la varianza campionaria di queste sottostazioni sono utilizzate per determinare il coefficiente di correlazione
  • acf, al contrario, utilizza la media campionaria generale e la varianza campionaria per determinare il coefficiente di correlazione.

Le differenze possono ridursi per le serie storiche più lunghe, ma sono abbastanza grandi per quelle brevi.

Rispetto Matlab, la funzione Pandas autocorr corrisponde probabilmente a fare Matlabs xcorr (cross-corr) con la (ritardato) serie stessa, invece di Matlab di autocorr, che calcola l'autocorrelazione campione (indovinare dalla documentazione, non posso convalidare questo perché non ho accesso a Matlab).

Vai a questa MWE di chiarimenti:

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() 

See this plot for the result

Statsmodels utilizza np.correlate di ottimizzare questo, ma questo è fondamentalmente come funziona.

0

Come suggerito nei commenti, il problema può essere diminuito, ma non completamente risolto, fornendo unbiased=True alla funzione . Utilizzando un ingresso casuale:

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)) 

uscita:

False 0.464562410987 
True 0.0820847168593