numpy.correlate를 사용하여 자기 상관을 어떻게 할 수 있습니까?


106

나는 숫자 세트의 자동 상관을 수행해야하는데, 이는 세트와 자체의 상관 관계라는 것을 이해합니다.

나는 numpy의 상관 함수를 사용하여 시도했지만 거의 항상 첫 번째 숫자가 가장 크지 않은 벡터를 제공하므로 결과를 믿지 않습니다 .

따라서이 질문은 실제로 두 가지 질문입니다.

  1. 정확히 무엇을 numpy.correlate하고 있습니까?
  2. 자동 상관을 수행하기 위해 어떻게 (또는 다른 것을) 사용할 수 있습니까?

정규화 된 자기 상관에 대한 정보는 stackoverflow.com/questions/12269834/… 를 참조하십시오 .
amcnabb

답변:


114

첫 번째 질문에 대답하려면 의 반전을 사용하여 numpy.correlate(a, v, mode)컨볼 루션을 수행 하고 지정된 모드에 의해 잘린 결과를 제공합니다. convolution정의 , C (t) = ∑ -∞ <i <∞ a i v t + i 여기서 -∞ <t <∞, -∞에서 ∞까지의 결과를 허용하지만 무한히 긴 값을 저장할 수는 없습니다. 정렬. 그래서 그것은 잘 려야하고, 그것이 모드가 들어오는 곳입니다. 3 가지 다른 모드가 있습니다 : 전체, 동일, 유효 :av

  • "전체"모드는 t둘 다에 대한 결과를 반환 a하고 v일부가 겹칩니다.
  • "same"모드는 가장 짧은 벡터 ( a또는 v) 와 길이가 같은 결과를 반환합니다 .
  • 경우에만 "유효"모드 결과를 반환 a하고 v서로 완전히 겹치는. 에 대한 문서numpy.convolve 는 모드에 대한 자세한 내용 을 제공합니다.

두 번째 질문, 나는 생각 numpy.correlate 한다 당신에게 자기 상관을 제공, 그냥 조금 더뿐만 아니라 당신을주고있다. 자기 상관은 특정 시간 차이에서 신호 또는 기능이 자신과 얼마나 유사한 지 찾는 데 사용됩니다. 시간 차이가 0이면 신호가 자체와 동일하므로 자기 상관이 가장 높아야하므로 자기 상관 결과 배열의 첫 번째 요소가 가장 클 것이라고 예상했습니다. 그러나 상관 관계는 0의 시간 차이에서 시작하지 않습니다. 음의 시간 차이에서 시작하여 0에 가까워진 다음 양의 값이됩니다. 즉, 다음을 예상했습니다.

자기 상관 (a) = ∑ -∞ <i <∞ a i v t + i 여기서 0 <= t <∞

하지만 당신이 얻은 것은 :

자기 상관 (a) = ∑ -∞ <i <∞ a i v t + i 여기서 -∞ <t <∞

당신이해야 할 일은 상관 관계 결과의 마지막 절반을 취하는 것입니다. 그것은 당신이 찾고있는 자기 상관이어야합니다. 이를 수행하는 간단한 파이썬 함수는 다음과 같습니다.

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

물론 이것이 x실제로 1-d 배열 인지 확인하려면 오류 검사가 필요합니다 . 또한,이 설명은 아마도 수학적으로 가장 엄격하지 않을 것입니다. convolution의 정의가 그것들을 사용하기 때문에 나는 무한대를 던지고 있었지만 그것이 반드시 자기 상관에 적용되는 것은 아닙니다. 따라서이 설명의 이론적 부분은 약간 불안정 할 수 있지만 실제 결과가 도움이되기를 바랍니다. 자기 상관에 대한 이러한 페이지 는 매우 유용하며 표기법과 무거운 개념을 살펴 보는 데 신경 쓰지 않는다면 훨씬 더 나은 이론적 배경을 제공 할 수 있습니다.


6
현재 numpy 빌드에서는 A. Levy가 제안한 것을 정확히 달성하기 위해 'same'모드를 지정할 수 있습니다. 함수의 몸체는 다음 읽을 수return numpy.correlate(x, x, mode='same')
데이비드 Zwicker을

13
@DavidZwicker하지만 결과는 다릅니다! np.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])} 첫 번째 항목가장 큰 항목 입니다 .
개발자

19
이 답변은 정규화되지 않은 자기 상관을 제공합니다.
amcnabb

4
@Developer가 올바른 슬라이싱을 제공한다고 생각합니다 [len(x)-1:]. 0 지연에서 시작합니다. fullmode는 결과 크기를 제공 하기 때문에 2*len(x)-1A.Levy [result.size/2:][len(x)-1:]. 그래도 int로 만드는 것이 좋습니다 [result.size//2:].
Jason

나는 파이썬 3.7에서 적어도 int로해야합니다 발견
kevinkayaks

25

자동 상관은 통계 및 컨볼 루션의 두 가지 버전으로 제공됩니다. 약간의 세부 사항을 제외하고는 둘 다 동일합니다. 통계 버전은 간격 [-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)])

9
당신이 원하는 numpy.corrcoef[x:-i], x[i:])[0,1]의 반환 값으로 두 번째 줄에있는 것은 corrcoef2 × 2 행렬
luispedro

통계적 자기 상관과 컨벌루션 자기 상관의 차이점은 무엇입니까?
Daniel 말한다 Reinstate Monica

1
@DanielPendergast : 번째 문장 답한다 : 그들은 모두 조금 상세를 제외하고 동일하게 수행 전 [통계] 구간 [-1,1]에있을 정규화
n1k31t4

21

numpy.corrcoef대신 함수를 사용하여 numpy.correlatet의 시차에 대한 통계적 상관 관계를 계산합니다.

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

"상관 계수"는 통계에서 사용되는 자기 상관이 아니라 신호 처리에 사용되는 자기 상관을 의미하지 않습니까? en.wikipedia.org/wiki/Autocorrelation#Signal_processing
다니엘 분석 재개 모니카 말한다

@DanielPendergast 저는 신호 처리에 익숙하지 않습니다. numpy 문서에서 : "Return Pearson product-moment correlation coefficients." 그게 신호 처리 버전인가요?
Ramón J Romero y Vigil

18

이 주제에 혼란을 더하는 두 가지가 있다고 생각합니다.

  1. 통계 대 신호 처리 정의 : 다른 사람들이 지적했듯이 통계에서 자동 상관 관계를 [-1,1]로 정규화합니다.
  2. 부분적 vs 비 부분적 평균 / 분산 : 시계열이 시차> 0에서 이동하면 중복 크기는 항상 <원래 길이보다 작습니다. 원래의 평균과 표준을 사용합니까 (부분이 아님), 아니면 항상 새 평균을 계산하고 항상 변화하는 겹침 (부분)을 사용하여 표준이 차이를 만듭니다. (아마도 이것에 대한 공식적인 용어가 있지만 지금은 "부분"을 사용하겠습니다).

나는 부분적 구별과 부분적 구별이없는 1d 배열의 자동 상관을 계산하는 5 개의 함수를 만들었습니다. 일부는 통계의 공식을 사용하고 일부는 신호 처리 의미에서 상관 관계를 사용하며 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()

다음은 출력 그림입니다.

여기에 이미지 설명 입력

5 개의 선 중 3 개가 겹치기 때문에 (보라색에서) 모두 볼 수 없습니다. 겹치는 부분은 모두 부분적이지 않은 자동 상관입니다. 이는 신호 처리 방법 ( np.correlate, FFT)의 계산이 각 중첩에 대해 다른 평균 / 표준을 계산하지 않기 때문입니다.

또한 fft, no padding, non-partial(빨간색 선) 결과는 FFT를 수행하기 전에 시계열을 0으로 채우지 않았으므로 원형 FFT입니다. 왜 다른 곳에서 배웠는지 자세히 설명 할 수 없습니다.


12

방금 똑같은 문제가 발생했을 때 몇 줄의 코드를 공유하고 싶습니다. 실제로 지금까지 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".


9

귀하의 질문 1은 여기에 몇 가지 훌륭한 답변에서 이미 광범위하게 논의되었습니다.

자기 상관의 수학적 속성만을 기반으로 신호의 자기 상관을 계산할 수있는 몇 줄의 코드를 공유하려고합니다. 즉, 자기 상관은 다음과 같은 방식으로 계산 될 수 있습니다.

  1. 신호에서 평균을 빼고 편향되지 않은 신호 얻기

  2. 편향되지 않은 신호의 푸리에 변환 계산

  3. 편향되지 않은 신호의 푸리에 변환의 각 값에 대한 제곱 노름을 취하여 신호의 전력 스펙트럼 밀도를 계산합니다.

  4. 전력 스펙트럼 밀도의 역 푸리에 변환 계산

  5. 편향되지 않은 신호의 제곱의 합으로 전력 스펙트럼 밀도의 역 푸리에 변환을 정규화하고 결과 벡터의 절반 만 가져옵니다.

이를 수행하는 코드는 다음과 같습니다.

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)

이것에 문제가있을 가능성이 있습니까? 다른 자동 상관 함수와의 결과를 일치시킬 수 없습니다. 기능은 비슷해 보이지만 다소 찌그러진 것 같습니다.
pindakaas

@pindakaas 좀 더 구체적으로 말씀해 주시겠습니까? 어떤 기능과 일치하지 않는지에 대한 정보를 제공하십시오.
Ruggero

왜 사용하지 p = np.abs(f)않습니까?
dylnan

@dylnan f의 구성 요소의 모듈 을 제공하는 반면 여기에는 f의 구성 요소의 정사각형 모듈 을 포함하는 벡터가 필요합니다 .
Ruggero

1
예,하지만 목록 이해를하는 것이 아마도 더 느리다는 것을 알고 계셨습니까?
Jason

2

저는 전산 생물 학자입니다. 저는 확률 적 과정의 시계열 두 쌍 사이의 자동 / 교차 상관을 계산해야 할 때 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

이전 답변 중 어느 것도 자동 / 교차 상관 관계를 다루지 않는 것 같습니다.이 답변이 저와 같은 확률 적 프로세스를 작업하는 누군가에게 유용 할 수 있기를 바랍니다.


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)

1

푸리에 변환과 컨볼 루션 정리 사용

시간 복잡도는 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:]

1

numpy.correlate의 대안은 statsmodels.tsa.stattools.acf () 에서 사용할 수 있습니다 . 이렇게하면 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 nlags에서 중지하는 것이지만 nlag=특정 응용 프로그램에 대한 옵션 으로 조정할 수 있습니다 . 기능 뒤에있는 통계 에 대한 페이지 하단에 인용문 이 있습니다 .


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`.

이는 '모드'정의없이 사용될 때 Numpy.correlate 함수가 두 입력 인수에 대해 동일한 벡터가 주어지면 스칼라를 반환한다는 것을 의미합니다 (예 : 자기 상관을 수행하는 데 사용될 때).


0

팬더가없는 간단한 솔루션 :

import numpy as np

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

0

pandas 데이터 타임 시리즈 수익률이 주어지면 통계적 자기 상관을 플로팅합니다.

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)

autocorrelation_plot()이 경우 왜 사용하지 않습니까? (cf. stats.stackexchange.com/questions/357300/… )
Qaswed
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.