Как я могу использовать numpy.correlate для автокорреляции? - PullRequest
87 голосов
/ 13 марта 2009

Мне нужно сделать автокорреляцию набора чисел, который, как я понимаю, является просто корреляцией набора с самим собой.

Я пробовал использовать коррелятную функцию numpy, но я не верю результату, поскольку он почти всегда дает вектор, в котором первое число не наибольшее, как должно быть.

Итак, этот вопрос действительно состоит из двух вопросов:

  1. Что именно делает numpy.correlate?
  2. Как я могу использовать его (или что-то еще) для автокорреляции?

Ответы [ 13 ]

98 голосов
/ 24 марта 2009

Чтобы ответить на ваш первый вопрос, numpy.correlate(a, v, mode) выполняет свертку a с обратным v и выдает результаты, ограниченные указанным режимом. определение свертки , C (t) = ∑ -∞ a i v t + i где -∞ «полный» режим возвращает результаты для каждого t, где и a, и v имеют некоторое перекрытие. «тот же» режим возвращает результат такой же длины, что и самый короткий вектор (a или v). «Действительный» режим возвращает результаты только тогда, когда a и v полностью перекрывают друг друга. Документация для numpy.convolve дает более подробную информацию о режимах. Что касается вашего второго вопроса, я думаю, numpy.correlate - это , дающее вам автокорреляцию, оно просто дает вам немного больше. Автокорреляция используется для определения того, насколько похож сигнал или функция на себя при определенной разнице во времени. При разнице во времени 0 автокорреляция должна быть максимальной, поскольку сигнал идентичен самому себе, поэтому вы ожидали, что первый элемент в массиве результатов автокорреляции будет наибольшим. Однако корреляция не начинается с разницы во времени 0. Она начинается с отрицательной разницы во времени, закрывается до 0 и затем становится положительной. То есть вы ожидали:

автокорреляция (а) = ∑ -∞ a i v t + i , где 0 <= t <∞ </p> Но то, что вы получили, было:

автокорреляция (а) = ∑ -∞ a i v t + i где -∞ Что вам нужно сделать, это взять вторую половину результата корреляции, и это должна быть автокорреляция, которую вы ищете. Простая функция Python для этого будет:

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

Вам, конечно, понадобится проверка ошибок, чтобы убедиться, что x на самом деле является массивом 1-го порядка. Кроме того, это объяснение, вероятно, не является наиболее математически строгим. Я разбрасывал бесконечности, потому что определение свертки использует их, но это не обязательно относится к автокорреляции. Таким образом, теоретическая часть этого объяснения может быть немного сомнительной, но, надеюсь, практические результаты окажутся полезными. Эти страницы об автокорреляции очень полезны и могут дать вам гораздо лучший теоретический фон, если вы не возражаете разобраться с обозначениями и сложными понятиями.

17 голосов
/ 18 февраля 2014

Используйте функцию numpy.corrcoef вместо numpy.correlate для расчета статистической корреляции для лага t:

def autocorr(x, t=1):
    return numpy.corrcoef(numpy.array([x[:-t], x[t:]]))
17 голосов
/ 02 ноября 2011

Автокорреляция поставляется в двух версиях: статистическая и свертка. Они оба делают то же самое, за исключением небольшой детализации: статистическая версия нормируется на интервал [-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)])
11 голосов
/ 13 июня 2013

Поскольку я столкнулся с той же проблемой, я хотел бы поделиться с вами несколькими строками кода. На самом деле на данный момент есть несколько довольно похожих сообщений об автокорреляции в stackoverflow. Если вы определяете автокорреляцию как a(x, L) = sum(k=0,N-L-1)((xk-xbar)*(x(k+L)-xbar))/sum(k=0,N-1)((xk-xbar)**2) [это определение, данное в функции a_correlate IDL, и оно согласуется с тем, что я вижу в ответе 2 на вопрос # 12269834 ], то, по-видимому, следующее дает правильные результаты :

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", как остальные.

10 голосов
/ 04 июля 2018

Я думаю, что есть две вещи, которые добавляют путаницу к этой теме:

  1. статистические против. Определение обработки сигнала: как уже указывали другие, в статистике мы нормализуем автокорреляцию в [-1,1].
  2. частичное против. Неполное среднее / дисперсия: когда временные ряды сдвигаются с задержкой> 0, их размер перекрытия всегда будет <исходной длины. Используем ли мы среднее и стандартное отклонение оригинала (не частичное), или всегда вычисляем новое среднее значение, и стандартное отклонение, используя постоянно меняющееся перекрытие (частичное), имеет значение. (Возможно, для этого есть формальный термин, но сейчас я буду использовать «частичный»). </li>

Я создал 5 функций, которые вычисляют автокорреляцию массива 1d с частичным v.s. не частичные различия. Некоторые используют формулу из статистики, некоторые используют коррелят в смысле обработки сигнала, что также может быть сделано через FFT. Но все результаты являются автокорреляциями в определении statistics , поэтому они иллюстрируют, как они связаны друг с другом. Код ниже:

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, поэтому это круговое FFT. Я не могу подробно объяснить, почему, это то, что я узнал из других источников.

9 голосов
/ 20 октября 2016

Ваш вопрос 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)
1 голос
/ 17 сентября 2018

Использование преобразования Фурье и теорема о свертке

Сложность времени 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]

Метод, предоставленный А. Леви, работает, но я проверил его на своем ПК, его сложность во времени, кажется, N * N

def autocorr(x):
    result = numpy.correlate(x, x, mode='full')
    return result[result.size/2:]
1 голос
/ 22 декабря 2015

Я использую 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)
0 голосов
/ 24 апреля 2019

Альтернатива 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 нлаг, но это можно настроить с помощью опции nlag= для вашего конкретного приложения. В нижней части страницы есть ссылка на статистику за функцией .

0 голосов
/ 08 октября 2018

График статистической автокорреляции с учетом времени данных панд Серии возвращений:

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...