Кросс-корреляция (временная корреляция) с пандами?

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

Я нашел различные вопросы и ответы/ссылки, в которых обсуждалось, как это сделать с помощью numpy, но это будет означать, что я должен превратить свои dataframes в массивы numpy. И поскольку мои временные ряды часто охватывают разные периоды, я боюсь, что столкнусь с хаосом.

редактировать

Проблема, которую я испытываю при использовании всех методов numpy/scipy, заключается в том, что они, как представляется, не знают о природе моих данных. Когда я сопоставляю временные ряды, начинающиеся с 1940 года, начиная с 1970 года, pandas corr знает об этом, тогда как np.correlate просто производит 1020 записей (длина более длинной серии), полный nan.

Различные Q по этому вопросу указывают на то, что должен быть способ решить проблему с разной длиной, но до сих пор я не видел никаких указаний о том, как использовать его для определенных периодов времени. Мне просто нужно сдвинуться на 12 месяцев с шагом 1, чтобы увидеть время максимальной корреляции в течение одного года.

Edit2

Некоторые минимальные данные выборки:

import pandas as pd
import numpy as np
dfdates1 = pd.date_range('01/01/1980', '01/01/2000', freq = 'MS')
dfdata1 = (np.random.random_integers(-30,30,(len(dfdates1)))/10.0) #My real data is from measurements, but random between -3 and 3 is fitting
df1 = pd.DataFrame(dfdata1, index = dfdates1)
dfdates2 = pd.date_range('03/01/1990', '02/01/2013', freq = 'MS')
dfdata2 = (np.random.random_integers(-30,30,(len(dfdates2)))/10.0)
df2 = pd.DataFrame(dfdata2, index = dfdates2)

Из-за различных этапов обработки эти dfs превращаются в df, индексированные с 1940 по 2015 год. Это должно воспроизвести это:

bigdates = pd.date_range('01/01/1940', '01/01/2015', freq = 'MS')
big1 = pd.DataFrame(index = bigdates)
big2 = pd.DataFrame(index = bigdates)
big1 = pd.concat([big1, df1],axis = 1)
big2 = pd.concat([big2, df2],axis = 1)

Это то, что я получаю, когда я коррелирую с пандами и переношу один набор данных:

In [451]: corr_coeff_0 = big1[0].corr(big2[0])
In [452]: corr_coeff_0
Out[452]: 0.030543266378853299
In [453]: big2_shift = big2.shift(1)
In [454]: corr_coeff_1 = big1[0].corr(big2_shift[0])
In [455]: corr_coeff_1
Out[455]: 0.020788314779320523

И пробуем scipy:

In [456]: scicorr = scipy.signal.correlate(big1,big2,mode="full")
In [457]: scicorr
Out[457]: 
array([[ nan],
       [ nan],
       [ nan],
       ..., 
       [ nan],
       [ nan],
       [ nan]])

которые в соответствии с whos является

scicorr               ndarray                       1801x1: 1801 elems, type 'float64', 14408 bytes

Но я бы хотел иметь 12 записей. /Edit2

Идея, которую я придумал, заключается в том, чтобы реализовать корреляцию времени-времени, например:

corr_coeff_0 = df1['Data'].corr(df2['Data'])
df1_1month = df1.shift(1)
corr_coeff_1 = df1_1month['Data'].corr(df2['Data'])
df1_6month = df1.shift(6)
corr_coeff_6 = df1_6month['Data'].corr(df2['Data'])
...and so on

Но это, вероятно, медленно, и я, вероятно, пытаюсь изобрести колесо здесь. Редактировать Этот подход, похоже, работает, и я поставил его в цикл, чтобы пройти через все 12 месяцев в году, но я все же предпочел бы встроенный метод.

Ответы

Ответ 1

Насколько я могу судить, нет встроенного метода, который делает именно то, что вы просите. Но если вы посмотрите на исходный код для метода панды серии autocorr, вы можете увидеть, что у вас есть правильная идея:

def autocorr(self, lag=1):
    """
    Lag-N autocorrelation

    Parameters
    ----------
    lag : int, default 1
        Number of lags to apply before performing autocorrelation.

    Returns
    -------
    autocorr : float
    """
    return self.corr(self.shift(lag))

Таким образом, простая функция кросс-ковариации с временной привязкой будет

def crosscorr(datax, datay, lag=0):
    """ Lag-N cross correlation. 
    Parameters
    ----------
    lag : int, default 0
    datax, datay : pandas.Series objects of equal length

    Returns
    ----------
    crosscorr : float
    """
    return datax.corr(datay.shift(lag))

Затем, если вы хотели посмотреть на кросс-корреляции в каждый месяц, вы могли бы сделать

 xcov_monthly = [crosscorr(datax, datay, lag=i) for i in range(12)]

Ответ 2

Существует более эффективный подход: вы можете создать функцию, которая сначала переместила ваш фреймворк, прежде чем вызывать corr().

Получить этот файл данных как пример:

d = {'prcp': [0.1,0.2,0.3,0.0], 'stp': [0.0,0.1,0.2,0.3]}
df = pd.DataFrame(data=d)

>>> df
   prcp  stp
0   0.1  0.0
1   0.2  0.1
2   0.3  0.2
3   0.0  0.3

Ваша функция сдвинуть другие столбцы (кроме цели):

def df_shifted(df, target=None, lag=0):
    if not lag and not target:
        return df       
    new = {}
    for c in df.columns:
        if c == target:
            new[c] = df[target]
        else:
            new[c] = df[c].shift(periods=lag)
    return  pd.DataFrame(data=new)

Предположим, что ваша цель сравнивает prcp (переменная осадка) с stp (атмосферное давление)

Если вы в настоящее время будете:

>>> df.corr()
      prcp  stp
prcp   1.0 -0.2
stp   -0.2  1.0

Но если вы переместили 1 (один) период на все остальные столбцы и сохранили цель (prcp):

df_new = df_shifted(df, 'prcp', lag=-1)

>>> print df_new
   prcp  stp
0   0.1  0.1
1   0.2  0.2
2   0.3  0.3
3   0.0  NaN

Обратите внимание, что теперь столбец stp сдвигается на одну позицию вверх в период, поэтому, если вы вызываете corr(), будет:

>>> df_new.corr()
      prcp  stp
prcp   1.0  1.0
stp    1.0  1.0

Итак, вы можете сделать с задержкой -1, -2, -n !!

Ответ 3

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

lagged_correlation = pd.DataFrame.from_dict(
    {x: [df[target].corr(df[x].shift(-t)) for t in range(max_lag)] for x in df.columns})

Таким образом, каждая строка соответствует разному значению задержки, а каждый столбец соответствует своей переменной (один из них является самой целью, дающей автокорреляцию).