В чем разница между Pandas ACF и statsmodel ACF?

Я вычисляю функцию автокорреляции для доходности акции. Для этого я протестировал две функции: функцию autocorr, встроенную в Pandas, и функцию acf, предоставленную statsmodels.tsa. Это делается в следующем MWE:

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

Я заметил, что предсказанные ими значения не идентичны:

введите описание изображения здесь

Что объясняет эту разницу и какие значения следует использовать?


person BML91    schedule 16.03.2016    source источник
comment
Глядя на документы, лаги по умолчанию равны 1 для версии pandas и 40 для statsmodel.   -  person EdChum    schedule 16.03.2016
comment
Попробуйте unbiased=True как вариант версии statsmodels.   -  person Josef    schedule 16.03.2016
comment
Вы поменяли местами метки на своем графике, я думаю, что unbiased=True должен увеличить коэффициенты автокорреляции.   -  person Josef    schedule 16.03.2016
comment
autocorr из pandas звонит numpy.corrcoef, а acf из statsmodels вызывает numpy.correlate. Я думаю, что копание в них может помочь найти корень различий в результатах.   -  person Primer    schedule 17.03.2016
comment
Является ли первый комментарий здесь ответом на вопрос? Было бы здорово решить эту проблему   -  person famargar    schedule 21.06.2017
comment
Это должна быть какая-то проблема нормализации, как обсуждается здесь: to-normalize" title="почему корреляция numpy и corrcoef возвращают разные значения и как нормализовать"> stackoverflow.com/questions/5639280/   -  person JohnE    schedule 22.06.2017
comment
@famargar второй и третий комментарии были ответами   -  person Uvar    schedule 07.07.2017


Ответы (3)


Разница между версиями Pandas и Statsmodels заключается в среднем вычитании и делении нормализации/дисперсии:

  • autocorr не делает ничего, кроме передачи подсерий исходной серии в np.corrcoef. Внутри этого метода выборочное среднее и выборочная дисперсия этих подсерий используются для определения коэффициента корреляции.
  • acf, напротив, использует выборочное среднее значение всего ряда и выборочную дисперсию для определения коэффициента корреляции.

Различия могут быть меньше для более длинных временных рядов, но достаточно велики для коротких.

По сравнению с Matlab, функция Pandas autocorr, вероятно, соответствует выполнению Matlabs xcorr (кросс-корр) с самим (отстающим) рядом, вместо Matlab autocorr, который вычисляет выборочную автокорреляцию (догадываясь из документов; я не могу проверить это, потому что у меня есть нет доступа к Matlab).

См. этот MWE для уточнения:

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

введите описание изображения здесь

Statsmodels использует np.correlate для оптимизации, но в основном это работает так.

person nikhase    schedule 05.08.2017
comment
Но какой из двух способов расчета автокорреляций лучше/правильнее? - person Sander van den Oord; 03.01.2019
comment
Путь statsmodels я считаю очевидным. Для справки, это также указано в Википедии. Чтобы проверить, является ли использование кросс-корреляции, как это делает pandas, также правильной оценкой, необходимо проверить литературу. К вашему сведению: хотя эта оценка statsmodels считается несмещенной, поскольку мы используем n-k вместо n, согласно Википедии она все же смещена, поскольку для расчета мы используем выборочное среднее и выборочную ковариацию. - person nikhase; 25.02.2019

Как указано в комментариях, проблему можно уменьшить, но не решить полностью, если передать unbiased=True функции statsmodels. Используя случайный ввод:

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

Выход:

False 0.464562410987
True 0.0820847168593
person Community    schedule 21.07.2017

В следующем примере функция Pandas autocorr() дает ожидаемые результаты, а функция statmodels acf() — нет.

Рассмотрим следующую серию:

import pandas as pd
s = pd.Series(range(10))

Мы ожидаем, что существует идеальная корреляция между этим рядом и любым из его запаздывающих рядов, и на самом деле это то, что мы получаем с помощью функции autocorr().

[ s.autocorr(lag=i) for i in range(10) ]
# [0.9999999999999999, 1.0, 1.0, 1.0, 1.0, 0.9999999999999999, 1.0, 1.0, 0.9999999999999999, nan]

Но используя acf() мы получаем другой результат:

from statsmodels.tsa.stattools import acf
acf(s)
# [ 1.          0.7         0.41212121  0.14848485 -0.07878788 
#  -0.25757576 -0.37575758 -0.42121212 -0.38181818 -0.24545455]

Если мы попробуем acf с adjusted=True, результат будет еще более неожиданным, потому что для некоторых задержек результат меньше -1 (обратите внимание, что корреляция должна быть в [-1, 1])

acf(s, adjusted=True)  # 'unbiased' is deprecated and 'adjusted' should be used instead
# [ 1.          0.77777778  0.51515152  0.21212121 -0.13131313 
#  -0.51515152 -0.93939394 -1.4040404  -1.90909091 -2.45454545]
person LoMaPh    schedule 30.10.2020