这是统计和信号处理之间不同的共同定义的结果。基本上,信号处理定义假设您要处理去趋势。统计定义假定减去均值就是您要做的所有去趋势化操作,并且会为您完成。
首先,让我们用一个独立的例子来演示这个问题:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from statsmodels.graphics import tsaplots
def label(ax, string):
ax.annotate(string, (1, 1), xytext=(-8, -8), ha='right', va='top',
size=14, xycoords='axes fraction', textcoords='offset points')
np.random.seed(1977)
data = np.random.normal(0, 1, 100).cumsum()
fig, axes = plt.subplots(nrows=4, figsize=(8, 12))
fig.tight_layout()
axes[0].plot(data)
label(axes[0], 'Raw Data')
axes[1].acorr(data, maxlags=data.size-1)
label(axes[1], 'Matplotlib Autocorrelation')
tsaplots.plot_acf(data, axes[2])
label(axes[2], 'Statsmodels Autocorrelation')
pd.tools.plotting.autocorrelation_plot(data, ax=axes[3])
label(axes[3], 'Pandas Autocorrelation')
# Remove some of the titles and labels that were automatically added
for ax in axes.flat:
ax.set(title='', xlabel='')
plt.show()
那么,为什么我说他们都是正确的?它们显然不同!
让我们编写我们自己的自相关函数来演示 plt.acorr 在做什么:
def acorr(x, ax=None):
if ax is None:
ax = plt.gca()
autocorr = np.correlate(x, x, mode='full')
autocorr /= autocorr.max()
return ax.stem(autocorr)
如果我们用我们的数据绘制它,我们将得到与plt.acorr 或多或少相同的结果(我没有正确标记滞后,只是因为我很懒):
fig, ax = plt.subplots()
acorr(data)
plt.show()
这是一个完全有效的自相关。这完全取决于您的背景是信号处理还是统计。
这是信号处理中使用的定义。假设您将处理去趋势数据(注意plt.acorr 中的detrend kwarg)。如果你想让它去趋势,你会明确地要求它(并且可能做一些比仅仅减去平均值更好的事情),否则不应该假设它。
在统计中,简单地减去平均值被认为是您想要做的去趋势。
所有其他函数都是在相关之前减去数据的平均值,类似于:
def acorr(x, ax=None):
if ax is None:
ax = plt.gca()
x = x - x.mean()
autocorr = np.correlate(x, x, mode='full')
autocorr /= autocorr.max()
return ax.stem(autocorr)
fig, ax = plt.subplots()
acorr(data)
plt.show()
但是,我们还有一个很大的不同。这纯粹是一个绘图约定。
在大多数信号处理教科书(无论如何我都看过)中,显示的是“完全”自相关,因此零滞后位于中心,结果在每一侧都是对称的。另一方面,R 有一个非常合理的约定,只显示它的一侧。 (毕竟对方完全是多余的。)统计绘图函数遵循 R 对流,plt.acorr 遵循 Matlab 所做的,这是相反的约定。
基本上,你会想要这个:
def acorr(x, ax=None):
if ax is None:
ax = plt.gca()
x = x - x.mean()
autocorr = np.correlate(x, x, mode='full')
autocorr = autocorr[x.size:]
autocorr /= autocorr.max()
return ax.stem(autocorr)
fig, ax = plt.subplots()
acorr(data)
plt.show()