Вопрос:

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

python math numpy numerical-methods

118328 просмотра

12 ответа

25284 Репутация автора

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

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

Итак, этот вопрос на самом деле два вопроса:

  1. Что именно делает numpy.correlate?
  2. Как я могу использовать это (или что-то еще), чтобы сделать автокорреляцию?
Автор: Ben Источник Размещён: 13.03.2009 05:07

Ответы (12)


93 плюса

11067 Репутация автора

Решение

Чтобы ответить на ваш первый вопрос, numpy.correlate(a, v, mode)выполняется свертка aс обратным vи выдача результатов в соответствии с указанным режимом. Определение свертки , С (т) = Е -∞ <я <∞ я v т + я где -∞ <т <∞, позволяет сделать результаты от -∞ до ∞, но вы , очевидно , не может хранить бесконечно долго массив. Таким образом, это должно быть обрезано, и именно здесь режим входит. Есть 3 различных режима: полный, тот же самый, и действительный:

  • «Полный» режим возвращает результаты для каждого, tгде оба aи vимеют некоторое перекрытие.
  • «тот же» режим возвращает результат той же длины, что и самый короткий вектор ( aили v).
  • «действительный» возвращает режим результаты только тогда , когда aи vполностью перекрывают друг друга. Документация для numpy.convolveдает более подробную информацию о режимах.

Что касается вашего второго вопроса, я думаю, что numpy.correlate он дает вам автокорреляцию, он просто дает вам немного больше. Автокорреляция используется для определения того, насколько сигнал или функция похожи на себя при определенной разнице во времени. При разнице во времени 0 автокорреляция должна быть наибольшей, поскольку сигнал идентичен самому себе, поэтому вы ожидали, что первый элемент в массиве результатов автокорреляции будет наибольшим. Однако корреляция не начинается с разницы во времени 0. Она начинается с отрицательной разницы во времени, закрывается до 0 и затем становится положительной. То есть вы ожидали

автокорреляция (а) = ∑ -∞ a i v t + i, где 0 <= t <∞

Но то, что вы получили, было:

автокорреляция (a) = ∑ -∞ a i v t + i, где -∞

Что вам нужно сделать, это взять вторую половину результата корреляции, и это должна быть автокорреляция, которую вы ищете. Простая функция Python для этого будет:

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

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

Автор: A. Levy Размещён: 24.03.2009 06:09

13 плюса

326 Репутация автора

Автокорреляция поставляется в двух версиях: статистическая и свертка. Они оба делают то же самое, за исключением небольшой детализации: статистическая версия нормируется на интервал [-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)])
Автор: jonathf Размещён: 02.11.2011 01:27

10 плюса

602 Репутация автора

Поскольку я столкнулся с той же проблемой, я хотел бы поделиться с вами несколькими строками кода. На самом деле на данный момент есть несколько довольно похожих сообщений об автокорреляции в 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"как другие.

Автор: maschu Размещён: 13.06.2013 02:52

15 плюса

11818 Репутация автора

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

def autocorr(x, t=1):
    return numpy.corrcoef(numpy.array([x[0:len(x)-t], x[t:len(x)]]))
Автор: Ramon J Romero y Vigil Размещён: 18.02.2014 07:10

0 плюса

570 Репутация автора

Я думаю, что настоящий ответ на вопрос ОП кратко содержится в этом отрывке из документации Numpy.correlate:

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

Это подразумевает, что при использовании без определения 'mode' функция Numpy.correlate будет возвращать скаляр, если задан один и тот же вектор для двух входных аргументов (т. Е. Когда используется для выполнения автокорреляции).

Автор: dbanas Размещён: 01.02.2015 09:17

1 плюс

1591 Репутация автора

Я использую 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)
Автор: litepresence Размещён: 22.12.2015 05:06

8 плюса

131 Репутация автора

Ваш вопрос 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)
Автор: Ruggero Размещён: 20.10.2016 12:46

0 плюса

49 Репутация автора

Я вычислительный биолог, и когда мне нужно было вычислить авто / взаимные корреляции между парами временных рядов случайных процессов, я понял, что np.correlate не выполняет нужную мне работу.

Действительно, в np.correlate, похоже, отсутствует усреднение по всем возможным парам временных точек на расстоянии \ tau.

Вот как я определил функцию, которая делает то, что мне нужно:

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

Мне кажется, что ни один из предыдущих ответов не охватывает этот случай авто / взаимной корреляции: надеюсь, что этот ответ может быть полезен для кого-то, работающего над случайными процессами, такими как я.

Автор: Orso Размещён: 12.04.2018 03:25

6 плюса

732 Репутация автора

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

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

Я создал 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()

Вот выходной показатель:

введите описание изображения здесь

Мы не видим все 5 линий, потому что 3 из них перекрываются (на фиолетовом). Перекрытия - это все неполные автокорреляции. Это потому, что вычисления из методов обработки сигналов ( np.correlate, FFT) не вычисляют различное среднее значение / стандартное отклонение для каждого перекрытия.

Также обратите внимание, что результат fft, no padding, non-partial(красная линия) отличается, потому что он не заполнял временные ряды нулями перед выполнением FFT, поэтому это круговое FFT. Я не могу подробно объяснить, почему, это то, что я узнал из других источников.

Автор: Jason Размещён: 04.07.2018 07:32

1 плюс

23 Репутация автора

Простое решение без панд:

import numpy as np

def auto_corrcoef(x):
   return np.corrcoef(x[1:-1], x[2:])[0,1]
Автор: dignitas Размещён: 23.07.2018 01:22

0 плюса

105 Репутация автора

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

Сложность времени 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:]
Автор: wwwjjj Размещён: 17.09.2018 06:20

0 плюса

1 Репутация автора

Построить статистическую автокорреляцию с учетом панд данных и данных.

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)
Автор: Antonio Catalano Размещён: 08.10.2018 12:42
Вопросы из категории :
32x32