我需要对一组数字进行自相关,据我所知这只是该集合与其自身的相关性。
我已经尝试使用NumPy的correlate函数,但我不相信结果,因为它几乎总是给出一个向量,其中第一个数字不是最大值,而它应该是。
因此,这个问题实际上有两个问题:
numpy.correlate
到底在做什么?- 我如何使用它(或其他东西)来进行自相关?
我需要对一组数字进行自相关,据我所知这只是该集合与其自身的相关性。
我已经尝试使用NumPy的correlate函数,但我不相信结果,因为它几乎总是给出一个向量,其中第一个数字不是最大值,而它应该是。
因此,这个问题实际上有两个问题:
numpy.correlate
到底在做什么?回答你的第一个问题,numpy.correlate(a, v, mode)
执行的是将a
与v
的反向卷积,并将结果剪裁为指定模式。卷积的定义C(t)=∑-∞ < i < ∞aivt+i,其中-∞ < t < ∞,允许结果从-∞到∞,但显然无法存储无限长的数组。因此必须剪裁,这就是模式发挥作用的地方。有3种不同的模式:full、same和valid:
t
都有一些重叠的a
和v
的结果。a
或v
)长度相同的结果。a
和v
完全重叠时返回结果。关于模式的更多细节,请参见numpy.convolve
的文档。numpy.correlate
实际上正在给您提供自相关性,它只是给您更多。自相关性用于查找信号或函数在某个时间差异处与其本身的相似程度。在时间差异为0时,自相关性应该最高,因为信号与其本身完全相同,因此您预期自相关结果数组中的第一个元素将是最大的。但是,相关性并没有从时间差为0开始。它从负时间差开始,接近0,然后变为正数。也就是说,您希望得到的是:
自相关(a) = ∑ -∞ < i < ∞ aivt+i 其中 0 <= t < ∞
但您得到的是:
自相关(a) = ∑ -∞ < i < ∞ aivt+i 其中 -∞ < t < ∞
您需要做的是取相关结果的后一半,那就是您要找的自相关性。一个简单的Python函数可以这样做:
def autocorr(x):
result = numpy.correlate(x, x, mode='full')
return result[result.size/2:]
当然,你需要进行错误检查以确保x
实际上是一个一维数组。此外,这个解释可能不是最数学严谨的。我一直在使用无限大,因为卷积的定义使用它们,但这并不一定适用于自相关。因此,这个解释的理论部分可能有些奇怪,但希望实际结果有所帮助。这些 页面关于自相关非常有帮助,如果你不介意穿过符号和重概念,可以给你更好的理论背景。
return numpy.correlate(x, x, mode='same')
。 - David Zwickernp.correlate(x,x,mode='full')[len(x)//2:] != np.correlate(x,x,mode='same')
。例如,x = [1,2,3,1,2]; np.correlate(x,x,mode='full');
{>>> array([ 2, 5, 11, 13, 19, 13, 11, 5, 2])
} np.correlate(x,x,mode='same');
{>>> array([11, 13, 19, 13, 11])
}。正确的方法是:np.correlate(x,x,mode='full')[len(x)-1:];
{>>> array([19, 13, 11, 5, 2])
},参见 第一个数 是 最大的数。 - Developer[len(x)-1:]
从0-lag开始。因为"full"模式给出结果大小为2*len(x)-1
,所以A.Levy的[result.size/2:]
与[len(x)-1:]
相同。不过最好将其转换为整数形式,例如[result.size//2:]
。 - Jason自相关有两种版本:统计和卷积。它们都做相同的事情,除了一个小细节:统计版本被标准化到区间[-1,1]。以下是如何执行统计版本的示例:
def acf(x, length=20):
return numpy.array([1]+[numpy.corrcoef(x[:-i], x[i:])[0,1] \
for i in range(1, length)])
numpy.corrcoef[x:-i], x[i:])[0,1]
,因为corrcoef
的返回值是一个2x2的矩阵。 - luispedro我认为这个主题会有两个混淆的地方:
我创建了5个函数来计算1d数组的自相关,包括部分和非部分的区别。有些使用统计学公式,有些使用信号处理中的相关性,也可以通过FFT完成。但所有结果都是自相关的统计学定义,因此它们说明了它们之间的联系。以下是代码:
import numpy
import matplotlib.pyplot as plt
def autocorr1(x,lags):
'''numpy.corrcoef, partial'''
corr=[1. if l==0 else numpy.corrcoef(x[l:],x[:-l])[0][1] for l in lags]
return numpy.array(corr)
def autocorr2(x,lags):
'''manualy compute, non partial'''
mean=numpy.mean(x)
var=numpy.var(x)
xp=x-mean
corr=[1. if l==0 else numpy.sum(xp[l:]*xp[:-l])/len(x)/var for l in lags]
return numpy.array(corr)
def autocorr3(x,lags):
'''fft, pad 0s, non partial'''
n=len(x)
# pad 0s to 2n-1
ext_size=2*n-1
# nearest power of 2
fsize=2**numpy.ceil(numpy.log2(ext_size)).astype('int')
xp=x-numpy.mean(x)
var=numpy.var(x)
# do fft and ifft
cf=numpy.fft.fft(xp,fsize)
sf=cf.conjugate()*cf
corr=numpy.fft.ifft(sf).real
corr=corr/var/n
return corr[:len(lags)]
def autocorr4(x,lags):
'''fft, don't pad 0s, non partial'''
mean=x.mean()
var=numpy.var(x)
xp=x-mean
cf=numpy.fft.fft(xp)
sf=cf.conjugate()*cf
corr=numpy.fft.ifft(sf).real/var/len(x)
return corr[:len(lags)]
def autocorr5(x,lags):
'''numpy.correlate, non partial'''
mean=x.mean()
var=numpy.var(x)
xp=x-mean
corr=numpy.correlate(xp,xp,'full')[len(x)-1:]/var/len(x)
return corr[:len(lags)]
if __name__=='__main__':
y=[28,28,26,19,16,24,26,24,24,29,29,27,31,26,38,23,13,14,28,19,19,\
17,22,2,4,5,7,8,14,14,23]
y=numpy.array(y).astype('float')
lags=range(15)
fig,ax=plt.subplots()
for funcii, labelii in zip([autocorr1, autocorr2, autocorr3, autocorr4,
autocorr5], ['np.corrcoef, partial', 'manual, non-partial',
'fft, pad 0s, non-partial', 'fft, no padding, non-partial',
'np.correlate, non-partial']):
cii=funcii(y,lags)
print(labelii)
print(cii)
ax.plot(lags,cii,label=labelii)
ax.set_xlabel('lag')
ax.set_ylabel('correlation coefficient')
ax.legend()
plt.show()
len(x) - l
来除,而是用len(x)
?现在这样会低估相关性,对吧?好吧,你可能会说只要l << len(x)
就可以了,这是一个鲁棒估计所必需的条件。 - Mahélen(x)
是“非部分”的规范,因此使用完整长度。 - Jason使用numpy.corrcoef
函数代替numpy.correlate
函数来计算延迟t的统计相关性:
def autocorr(x, t=1):
return numpy.corrcoef(numpy.array([x[:-t], x[t:]]))
你的问题1已经在这里的一些优秀回答中得到了广泛讨论。
我想与您分享几行代码,可以基于自相关的数学性质计算信号的自相关。也就是说,可以按以下方式计算自相关:
从信号中减去均值并获得无偏信号
计算无偏信号的傅里叶变换
通过对无偏信号的傅里叶变换的每个值求平方范数来计算信号的功率谱密度
计算功率谱密度的反傅里叶变换
通过无偏信号的平方和来规范化功率谱密度的反傅里叶变换,并仅取结果向量的一半
实现此操作的代码如下:
def autocorrelation (x) :
"""
Compute the autocorrelation of the signal, based on the properties of the
power spectral density of the signal.
"""
xp = x-np.mean(x)
f = np.fft.fft(xp)
p = np.array([np.real(v)**2+np.imag(v)**2 for v in f])
pi = np.fft.ifft(p)
return np.real(pi)[:x.size/2]/np.sum(xp**2)
numpy.correlate(x, x, mode='same')
,但是完整函数 numpy.correlate(x, x, mode='full')
呢?我们能否也使用FFT来实现它呢? - Feodorannp.abs(f)**2
比列表推导式要快得多。原则上,通过使用 f.real**2 + f.imag**2
避免不必要的平方甚至更快,但是在这里效果微不足道,因为FFT当然比一些基本的乘法/加法慢。 - Feodoran由于我刚刚遇到同样的问题,我想与你分享几行代码。实际上,stackoverflow 上已经有几篇关于自相关性的相似帖子。如果您将自相关定义为 a(x, L) = sum(k=0,N-L-1)((xk-xbar)*(x(k+L)-xbar))/sum(k=0,N-1)((xk-xbar)**2)
[这是IDL的a_correlate函数中给出的定义,并且它与问题#12269834的答案2一致],那么以下似乎会给出正确的结果:
import numpy as np
import matplotlib.pyplot as plt
# generate some data
x = np.arange(0.,6.12,0.01)
y = np.sin(x)
# y = np.random.uniform(size=300)
yunbiased = y-np.mean(y)
ynorm = np.sum(yunbiased**2)
acor = np.correlate(yunbiased, yunbiased, "same")/ynorm
# use only second half
acor = acor[len(acor)/2:]
plt.plot(acor)
plt.show()
你可以看到,我已经用正弦曲线和均匀随机分布进行了测试,两个结果都符合我的预期。请注意,我使用了mode="same"
而不是其他人使用的mode="full"
。
在statsmodels.tsa.stattools.acf()中提供了numpy.correlate的替代方法。它产生一个连续递减的自相关函数,就像OP所描述的那样。实现它相当简单:
from statsmodels.tsa import stattools
# x = 1-D array
# Yield normalized autocorrelation function of number lags
autocorr = stattools.acf( x )
# Get autocorrelation coefficient at lag = 1
autocorr_coeff = autocorr[1]
默认行为是在40个滞后值处停止,但可以使用nlag=
选项来调整您特定应用程序的滞后值。该函数背后的统计数据有一个引用,请参考页面底部的文献。np.correlate
不能满足我的需求。np.correlate
似乎缺少距离为d的所有可能时间点对之间的平均值。def autocross(x, y):
c = np.correlate(x, y, "same")
v = [c[i]/( len(x)-abs( i - (len(x)/2) ) ) for i in range(len(c))]
return v
N = len(x); v = c/(N - np.abs(np.arange(N) - N/2))
。 - jared使用傅里叶变换和卷积定理
时间复杂度为N*log(N)
def autocorr1(x):
r2=np.fft.ifft(np.abs(np.fft.fft(x))**2).real
return r2[:len(x)//2]
def autocorr2(x):
r2=np.fft.ifft(np.abs(np.fft.fft(x))**2).real
c=(r2/x.shape-np.mean(x)**2)/np.std(x)**2
return c[:len(x)//2]
A. Levy提供的方法可行,但我在我的电脑上测试过,它的时间复杂度似乎是N*N
def autocorr(x):
result = numpy.correlate(x, x, mode='full')
return result[result.size/2:]
没有使用pandas的简单解决方案:
import numpy as np
def auto_corrcoef(x):
return np.corrcoef(x[1:-1], x[2:])[0,1]