pandas ACF 和 statsmodel ACF 有什么区别?
What's the difference between pandas ACF and statsmodel ACF?
我正在计算股票 returns 的自相关函数。为此,我测试了两个函数,Pandas 中内置的 autocorr
函数和 statsmodels.tsa
提供的 acf
函数。这是在以下 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')
我注意到他们预测的值并不相同:
造成这种差异的原因是什么,应该使用哪些值?
正如评论中所建议的,通过向 statsmodels
函数提供 unbiased=True
可以减少问题,但不能完全解决。使用随机输入:
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
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
对其进行优化,但这基本上就是它的工作原理。
在下面的示例中,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]
我正在计算股票 returns 的自相关函数。为此,我测试了两个函数,Pandas 中内置的 autocorr
函数和 statsmodels.tsa
提供的 acf
函数。这是在以下 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')
我注意到他们预测的值并不相同:
造成这种差异的原因是什么,应该使用哪些值?
正如评论中所建议的,通过向 statsmodels
函数提供 unbiased=True
可以减少问题,但不能完全解决。使用随机输入:
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
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
对其进行优化,但这基本上就是它的工作原理。
在下面的示例中,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]