如何使用numpy.correlate进行自相关?

时间:2009-03-13 17:07:53

标签: python math numpy numerical-methods

我需要对一组数字进行自相关,据我所知,这只是集合与自身的相关性。

我尝试使用numpy的相关函数,但我不相信结果,因为它几乎总是给出一个向量,其中第一个数字不是最大,因为它应该是

所以,这个问题实际上是两个问题:

  1. numpy.correlate到底在做什么?
  2. 如何使用它(或其他东西)进行自动关联?

13 个答案:

答案 0 :(得分:98)

要回答您的第一个问题,numpy.correlate(a, v, mode)正在以a的反向执行v的卷积,并按指定的模式剪切结果。 definition of convolution,C(t)=Σ-∞<我< ∞ a i v t + i 其中-∞< t< ∞,允许从-∞到∞的结果,但显然你不能存储一个无限长的数组。所以它必须被剪裁,这就是模式的用武之地。有3种不同的模式:完整,相同,和有效:

  • “完整”模式会返回ta都有重叠的v的每个a的结果。
  • “same”模式返回与最短向量(va)长度相同的结果。
  • “有效”模式仅在vnumpy.convolve完全相互重叠时才返回结果。 numpy.correlate的{​​{3}}提供了有关模式的更多详细信息。

对于你的第二个问题,我认为def autocorr(x): result = numpy.correlate(x, x, mode='full') return result[result.size/2:] 给你自相关,它只是给你一点点。自相关用于找出信号或函数在某个时间差处与自身的相似程度。在时间差为0时,自相关应该是最高的,因为信号与其自身相同,因此您期望自相关结果数组中的第一个元素将是最大的。但是,相关性不是从0的时间差开始。它从负时间差开始,接近0,然后变为正。也就是说,你期待:

自相关(a)=Σ-∞&lt;我&lt; ∞ a i v t + i 其中0 <= t&lt; ∞

但你得到的是:

自相关(a)=Σ-∞&lt;我&lt; ∞ a i v t + i 其中-∞&lt; t&lt; ∞

您需要做的是获取相关结果的后半部分,这应该是您正在寻找的自相关。一个简单的python函数就是:

x

当然,您需要进行错误检查以确保{{1}}实际上是一维数组。此外,这种解释可能不是数学上最严格的。由于卷积的定义使用了无限性,我一直在无穷无尽,但这并不一定适用于自相关。因此,这种解释的理论部分可能略显不足,但希望实际结果是有帮助的。关于自相关的documentation These非常有帮助,如果您不介意使用符号和繁重的概念,可以为您提供更好的理论背景。

答案 1 :(得分:17)

使用numpy.corrcoef函数代替numpy.correlate来计算滞后t的统计相关性:

def autocorr(x, t=1):
    return numpy.corrcoef(numpy.array([x[:-t], x[t:]]))

答案 2 :(得分:16)

自动关联有两个版本:统计和卷积。除了一些细节之外,它们都是相同的:统计版本被标准化为区间[-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)])

答案 3 :(得分:11)

由于我遇到了同样的问题,我想与您分享几行代码。事实上,目前有一些关于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()

如你所见,我用sin曲线和均匀的随机分布测试了这个,两个结果看起来都像我期望的那样。请注意,我使用的是mode="same"而不是mode="full"

答案 4 :(得分:10)

我认为有两件事使该主题更加混乱:

    统计与诉信号处理定义:正如其他人所指出的,在统计中,我们将自相关归一化为[-1,1]。
  1. 部分诉非局部均值/方差:当时间序列在滞后> 0时移动时,它们的重叠大小将始终<原始长度。我们使用原始(非局部)的均值和标准差,还是始终使用不断变化的重叠(局部)计算新的均值和标准差会有所不同。 (对此可能有一个正式术语,但我现在要使用“部分”)。

我创建了5个函数,它们用部分v.s计算一维数组的自相关。非局部区别。一些使用统计中的公式,一些使用在信号处理意义上相关,这也可以通过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()

这是输出图:

enter image description here

我们看不到全部5条线,因为其中3条线重叠(在紫色处)。重叠都是非局部自相关。这是因为信号处理方法(np.correlate,FFT)的计算不会为每个重叠计算出不同的均值/标准差。

还要注意,fft, no padding, non-partial(红线)结果是不同的,因为在进行FFT之前,时间序列未填充0s,因此是循环FFT。我无法详细解释原因,这就是我从其他地方学到的。

答案 5 :(得分:9)

Your question 1 has been already extensively discussed in several excellent answers here.

I thought to share with you a few lines of code that allow you to compute the autocorrelation of a signal based only on the mathematical properties of the autocorrelation. That is, the autocorrelation may be computed in the following way:

  1. subtract the mean from the signal and obtain an unbiased signal

  2. compute the Fourier transform of the unbiased signal

  3. compute the power spectral density of the signal, by taking the square norm of each value of the Fourier transform of the unbiased signal

  4. compute the inverse Fourier transform of the power spectral density

  5. normalize the inverse Fourier transform of the power spectral density by the sum of the squares of the unbiased signal, and take only half of the resulting vector

The code to do this is the following:

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)

答案 6 :(得分:1)

我使用talib.CORREL这样的自相关,我怀疑你可以对其他包做同样的事情:

def autocorrelate(x, period):

    # x is a deep indicator array 
    # period of sample and slices of comparison

    # oldest data (period of input array) may be nan; remove it
    x = x[-np.count_nonzero(~np.isnan(x)):]
    # subtract mean to normalize indicator
    x -= np.mean(x)
    # isolate the recent sample to be autocorrelated
    sample = x[-period:]
    # create slices of indicator data
    correls = []
    for n in range((len(x)-1), period, -1):
        alpha = period + n
        slices = (x[-alpha:])[:period]
        # compare each slice to the recent sample
        correls.append(ta.CORREL(slices, sample, period)[-1])
    # fill in zeros for sample overlap period of recent correlations    
    for n in range(period,0,-1):
        correls.append(0)
    # oldest data (autocorrelation period) will be nan; remove it
    correls = np.array(correls[-np.count_nonzero(~np.isnan(correls)):])      

    return correls

# CORRELATION OF BEST FIT
# the highest value correlation    
max_value = np.max(correls)
# index of the best correlation
max_index = np.argmax(correls)

答案 7 :(得分:0)

我认为OP问题的真正答案简明扼要地包含在Numpy.correlate文档的摘录中:

mode : {'valid', 'same', 'full'}, optional
    Refer to the `convolve` docstring.  Note that the default
    is `valid`, unlike `convolve`, which uses `full`.

这意味着,在没有&#39;模式的情况下使用&#39;定义时,Numpy.correlate函数将返回一个标量,当给它两个输入参数的相同向量时(即 - 当用于执行自相关时)。

答案 8 :(得分:0)

我是计算生物学家,当我不得不计算随机过程时间序列之间的自相关/交叉相关时,我意识到np.correlate没有完成我需要的工作。

事实上,np.correlate似乎缺少的是 在距离上所有可能的时间点 的平均值。

以下是我如何根据需要定义函数:

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

在我看来,之前的答案都没有涵盖这个自动/互相关的实例:希望这个答案可能对像我这样的随机过程的人有用。

答案 9 :(得分:0)

没有熊猫的简单解决方案:

import numpy as np

def auto_corrcoef(x):
   return np.corrcoef(x[1:-1], x[2:])[0,1]

答案 10 :(得分:0)

使用傅立叶变换和卷积定理

时间复杂度为 N * log(N)

def autocorr1(x):
    r2=np.fft.ifft(np.abs(np.fft.fft(x))**2).real
    return r2[:len(x)//2]

这是一个标准化且无偏见的版本,它也是 N * log(N)

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提供的方法有效,但我在PC上对其进行了测试,其时间复杂度似乎为 N * N

def autocorr(x):
    result = numpy.correlate(x, x, mode='full')
    return result[result.size/2:]

答案 11 :(得分:0)

在给定pandas datatime系列收益的情况下,绘制统计自相关图

import matplotlib.pyplot as plt

def plot_autocorr(returns, lags):
    autocorrelation = []
    for lag in range(lags+1):
        corr_lag = returns.corr(returns.shift(-lag)) 
        autocorrelation.append(corr_lag)
    plt.plot(range(lags+1), autocorrelation, '--o')
    plt.xticks(range(lags+1))
    return np.array(autocorrelation)

答案 12 :(得分:0)

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=选项进行调整。页面底部有statistics behind the function的引文。