Làm cách nào để sử dụng numpy.correlate để thực hiện tự tương quan?


106

Tôi cần thực hiện tự động tương quan của một tập hợp số, theo tôi hiểu, nó chỉ là tương quan của tập hợp với chính nó.

Tôi đã thử nó bằng cách sử dụng hàm tương quan của numpy, nhưng tôi không tin vào kết quả, vì nó hầu như luôn đưa ra một vectơ trong đó số đầu tiên không phải là số lớn nhất, đúng như vậy.

Vì vậy, câu hỏi này thực sự là hai câu hỏi:

  1. Chính xác thì numpy.correlateđang làm gì?
  2. Làm cách nào tôi có thể sử dụng nó (hoặc thứ gì đó khác) để thực hiện tự động tương quan?

Xem thêm: stackoverflow.com/questions/12269834/… để biết thông tin về tự tương quan chuẩn hóa.
amcnabb

Câu trả lời:


114

Để trả lời câu hỏi đầu tiên của bạn, numpy.correlate(a, v, mode)là thực hiện phép tích chập avới đảo ngược của vvà đưa ra kết quả được cắt theo chế độ đã chỉ định. Các định nghĩa của chập , C (t) = Σ -∞ <i <∞ một i v t + i nơi -∞ <t <∞, cho phép kết quả từ -∞ đến ∞, nhưng bạn rõ ràng là không thể lưu trữ một dài vô hạn mảng. Vì vậy, nó phải được cắt bớt, và đó là nơi chế độ đi vào. Có 3 chế độ khác nhau: đầy đủ, giống nhau & hợp lệ:

  • chế độ "đầy đủ" trả về kết quả cho mọi tnơi cả hai avcó một số chồng chéo.
  • chế độ "giống nhau" trả về một kết quả có cùng độ dài với vectơ ngắn nhất ( ahoặc v).
  • chế độ "hợp lệ" chỉ trả về kết quả khi avhoàn toàn chồng chéo lên nhau. Các tài liệu hướng dẫn cho numpy.convolvecho chi tiết hơn về các phương thức.

Đối với câu hỏi thứ hai của bạn, tôi nghĩ numpy.correlate đang cung cấp cho bạn sự tự tương quan, nó chỉ cung cấp cho bạn nhiều hơn một chút. Tự tương quan được sử dụng để tìm tín hiệu hoặc chức năng tương tự như thế nào với chính nó tại một thời điểm khác biệt nhất định. Tại thời điểm chênh lệch 0, mức độ tương quan tự động sẽ là cao nhất vì tín hiệu giống hệt với chính nó, vì vậy bạn mong đợi rằng phần tử đầu tiên trong mảng kết quả tự tương quan sẽ là lớn nhất. Tuy nhiên, mối tương quan không bắt đầu ở chênh lệch thời gian bằng 0. Nó bắt đầu ở chênh lệch thời gian âm, đóng về 0 và sau đó chuyển sang số dương. Đó là, bạn đã mong đợi:

tự tương quan (a) = ∑ -∞ <i <∞ a i v t + i trong đó 0 <= t <∞

Nhưng những gì bạn nhận được là:

tự tương quan (a) = ∑ -∞ <i <∞ a i v t + i trong đó -∞ <t <∞

Những gì bạn cần làm là lấy nửa cuối của kết quả tương quan của bạn, và đó phải là tự tương quan mà bạn đang tìm kiếm. Một hàm python đơn giản để làm điều đó sẽ là:

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

Tất nhiên, bạn sẽ cần kiểm tra lỗi để đảm bảo rằng đó xthực sự là mảng 1-d. Ngoài ra, lời giải thích này có lẽ không chặt chẽ về mặt toán học. Tôi đã xoay quanh các số vô hạn bởi vì định nghĩa của tích chập sử dụng chúng, nhưng điều đó không nhất thiết áp dụng cho tự tương quan. Vì vậy, phần lý thuyết của lời giải thích này có thể hơi khó hiểu, nhưng hy vọng kết quả thực tế là hữu ích. Những trang này về tự tương quan khá hữu ích và có thể cung cấp cho bạn nền tảng lý thuyết tốt hơn nhiều nếu bạn không ngại lội qua các ký hiệu và khái niệm nặng nề.


6
Trong các bản dựng hiện tại của numpy, chế độ 'giống nhau' có thể được chỉ định để đạt được chính xác những gì A. Levy đề xuất. Nội dung của hàm sau đó có thể đọcreturn numpy.correlate(x, x, mode='same')
David Zwicker

13
@DavidZwicker nhưng các lần thay đổi lại khác nhau! np.correlate(x,x,mode='full')[len(x)//2:] != np.correlate(x,x,mode='same'). Ví dụ: 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])}. Câu đúng là: np.correlate(x,x,mode='full')[len(x)-1:];{ >>> array([19, 13, 11, 5, 2])} xem mục đầu tiênmục lớn nhất .
Nhà phát triển

19
Lưu ý rằng câu trả lời này đưa ra hiện tượng tự tương quan không chuẩn hóa.
amcnabb

4
Tôi nghĩ rằng @Developer đưa ra sự phân chia chính xác: [len(x)-1:]bắt đầu từ độ trễ 0. Bởi vì fullchế độ cung cấp kích thước kết quả 2*len(x)-1, A.Levy's [result.size/2:]giống như [len(x)-1:]. Tốt hơn là hãy biến nó thành một int, chẳng hạn như [result.size//2:].
Jason

Tôi thấy nó phải là một int, ít nhất là trong python 3.7
kevinkayaks

25

Tương quan tự động có hai phiên bản: thống kê và tích chập. Cả hai đều làm như nhau, ngoại trừ một chi tiết nhỏ: Phiên bản thống kê được chuẩn hóa để nằm trong khoảng [-1,1]. Đây là một ví dụ về cách bạn thực hiện thống kê:

def acf(x, length=20):
    return numpy.array([1]+[numpy.corrcoef(x[:-i], x[i:])[0,1]  \
        for i in range(1, length)])

9
Bạn muốn numpy.corrcoef[x:-i], x[i:])[0,1]trong dòng thứ hai là giá trị trả về corrcoeflà một ma trận 2x2
luispedro

Sự khác biệt giữa tự tương quan thống kê và tích chập là gì?
Daniel nói Hãy phục hồi Monica vào

1
@DanielPendergast: Câu trả lời thứ hai: Cả hai đều làm như vậy, ngoại trừ một chi tiết nhỏ: Các cựu [thống kê] được chuẩn hóa để được vào khoảng [-1,1]
n1k31t4

21

Sử dụng numpy.corrcoefhàm thay vì numpy.correlateđể tính toán tương quan thống kê cho độ trễ của t:

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

Không phải "hệ số tương quan" đề cập đến tự tương quan được sử dụng trong xử lý tín hiệu và không phải tự tương quan được sử dụng trong thống kê? vi.wikipedia.org/wiki/Autocorrelation#Signal_processing
Daniel nói Hãy phục hồi Monica vào

@DanielPendergast Tôi không rành về xử lý tín hiệu. Từ tài liệu numpy: "Trả về hệ số tương quan thời điểm sản phẩm Pearson.". Đó có phải là phiên bản xử lý tín hiệu không?
Ramón J Romero y Vigil

18

Tôi nghĩ rằng có 2 điều làm tăng thêm sự nhầm lẫn cho chủ đề này:

  1. định nghĩa thống kê và xử lý tín hiệu: như những người khác đã chỉ ra, trong thống kê, chúng tôi chuẩn hóa tự động tương quan thành [-1,1].
  2. phương sai / trung bình một phần so với không một phần: khi thời gian thay đổi ở độ trễ> 0, kích thước chồng chéo của chúng sẽ luôn <độ dài ban đầu. Chúng ta có sử dụng giá trị trung bình và điểm chuẩn của giá trị gốc (không một phần) hay luôn tính toán giá trị trung bình và điểm trung bình mới bằng cách sử dụng chồng chéo luôn thay đổi (một phần) tạo ra sự khác biệt. (Có lẽ có một thuật ngữ chính thức cho điều này, nhưng tôi sẽ sử dụng "một phần" bây giờ).

Tôi đã tạo 5 hàm tính toán tự động tương quan của một mảng 1d, với sự khác biệt một phần và không một phần. Một số sử dụng công thức từ thống kê, một số sử dụng tương quan theo nghĩa xử lý tín hiệu, cũng có thể được thực hiện thông qua FFT. Nhưng tất cả các kết quả đều là tương quan tự động trong định nghĩa thống kê , vì vậy chúng minh họa cách chúng được liên kết với nhau. Mã bên dưới:

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()

Đây là con số đầu ra:

nhập mô tả hình ảnh ở đây

Chúng tôi không nhìn thấy tất cả 5 dòng vì 3 trong số chúng chồng lên nhau (ở màu tím). Các phần chồng chéo đều là các tương quan tự động không từng phần. Điều này là do các tính toán từ các phương pháp xử lý tín hiệu ( np.correlate, FFT) không tính toán trung bình / std khác nhau cho mỗi chồng chéo.

Cũng lưu ý rằng fft, no padding, non-partialkết quả (đường màu đỏ) là khác nhau, vì nó không đệm thời gian bằng 0 trước khi thực hiện FFT, vì vậy nó là FFT tròn. Tôi không thể giải thích chi tiết tại sao, đó là những gì tôi học được từ những nơi khác.


12

Vì tôi vừa gặp phải vấn đề tương tự, tôi muốn chia sẻ một vài dòng mã với bạn. Trên thực tế, có một số bài đăng khá giống nhau về tự tương quan trong stackoverflow cho đến nay. Nếu bạn định nghĩa tự tương quan là a(x, L) = sum(k=0,N-L-1)((xk-xbar)*(x(k+L)-xbar))/sum(k=0,N-1)((xk-xbar)**2)[đây là định nghĩa được đưa ra trong hàm a_correlate của IDL và nó đồng ý với những gì tôi thấy trong câu trả lời 2 của câu hỏi # 12269834 ], thì điều sau có vẻ cho kết quả chính xác:

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()

Như bạn thấy, tôi đã kiểm tra điều này với đường cong sin và phân phối ngẫu nhiên đồng nhất, và cả hai kết quả đều giống như tôi mong đợi. Lưu ý rằng tôi đã sử dụng mode="same"thay vì mode="full"như những người khác đã làm.


9

Câu hỏi 1 của bạn đã được thảo luận rộng rãi trong một số câu trả lời xuất sắc ở đây.

Tôi muốn chia sẻ với bạn một vài dòng mã cho phép bạn tính toán tự tương quan của một tín hiệu chỉ dựa trên các đặc tính toán học của tự tương quan. Tức là, tự tương quan có thể được tính theo cách sau:

  1. trừ giá trị trung bình khỏi tín hiệu và thu được tín hiệu không chệch

  2. tính toán biến đổi Fourier của tín hiệu không chệch

  3. tính toán mật độ phổ công suất của tín hiệu, bằng cách lấy chuẩn bình phương của mỗi giá trị của biến đổi Fourier của tín hiệu không chệch

  4. tính toán biến đổi Fourier nghịch đảo của mật độ phổ công suất

  5. chuẩn hóa phép biến đổi Fourier ngược của mật độ phổ công suất bằng tổng bình phương của tín hiệu không chệch và chỉ lấy một nửa vectơ kết quả

Mã để thực hiện việc này như sau:

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)

Có thể là có điều gì đó sai với điều này? Tôi không thể đối sánh kết quả của nó với các chức năng tương quan tự động khác. Chức năng trông tương tự nhưng có vẻ hơi nhỏ.
pindakaas

@pindakaas bạn có thể cụ thể hơn được không? vui lòng cung cấp thông tin về sự khác biệt mà bạn tìm thấy, với những chức năng nào.
Ruggero

Tại sao không sử dụng p = np.abs(f)?
dylnan

@dylnan Điều đó sẽ cung cấp cho các mô-đun của các thành phần của f, trong khi ở đó chúng ta muốn ở đây một vectơ chứa các mô-đun bình phương của các thành phần của f.
Ruggero

1
Vâng, nhưng bạn có nhận ra rằng việc hiểu danh sách có thể còn chậm hơn.
Jason

2

Tôi là một nhà sinh học tính toán và khi tôi phải tính toán các tương quan tự động / chéo giữa các cặp quy trình ngẫu nhiên theo chuỗi thời gian, tôi nhận ra rằng điều đó np.correlatekhông thực hiện được công việc mà tôi cần.

Thật vậy, điều dường như bị thiếu np.correlatelà giá trị trung bình của tất cả các cặp điểm thời gian có thể có ở khoảng cách 𝜏.

Đây là cách tôi xác định một hàm thực hiện những gì tôi cần:

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

Đối với tôi, dường như không có câu trả lời nào bao gồm trường hợp tự động / tương quan chéo này: hy vọng câu trả lời này có thể hữu ích cho ai đó đang làm việc trên các quy trình ngẫu nhiên như tôi.


1

Tôi sử dụng talib.CORREL để tự tương quan như thế này, tôi nghi ngờ bạn có thể làm tương tự với các gói khác:

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

Sử dụng phép biến đổi Fourier và định lý tích chập

Thời gian bổ sung là N * log (N)

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

Đây là phiên bản chuẩn hóa và không thiên vị, nó cũng là 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]

Phương pháp do A. Levy cung cấp có hiệu quả, nhưng tôi đã thử nghiệm nó trong PC của mình, tính bổ sung về thời gian của nó dường như là N * N

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

1

Một giải pháp thay thế cho numpy.correlate có sẵn trong statsmodels.tsa.stattools.acf () . Điều này tạo ra một hàm tự tương quan giảm liên tục giống như hàm được OP mô tả. Thực hiện nó khá đơn giản:

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]

Hành vi mặc định là dừng ở 40 nlags, nhưng điều này có thể được điều chỉnh với nlag=tùy chọn cho ứng dụng cụ thể của bạn. Có một trích dẫn ở cuối trang cho các thống kê đằng sau chức năng .


0

Tôi nghĩ câu trả lời thực sự cho câu hỏi của OP được trình bày ngắn gọn trong đoạn trích này từ tài liệu Numpy.correlate:

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

Điều này ngụ ý rằng, khi được sử dụng không có định nghĩa 'chế độ', hàm Numpy.correlate sẽ trả về một đại lượng vô hướng, khi được cung cấp cùng một vectơ cho hai đối số đầu vào của nó (tức là - khi được sử dụng để thực hiện tự tương quan).


0

Một giải pháp đơn giản mà không có gấu trúc:

import numpy as np

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

0

Vẽ đồ thị tự tương quan thống kê cho một loạt dữ liệu gấu trúc Chuỗi lợi nhuận:

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)

Tại sao không sử dụng autocorrelation_plot()trong trường hợp này? (xem stats.stackexchange.com/questions/357300/… )
Đã hỏi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.