Кросс-корреляция (временная задержка) с пандами?
У меня есть различные временные ряды, которые я хочу коррелировать - или, скорее, взаимно коррелировать - друг с другом, чтобы выяснить, в какой временной лаг коэффициент корреляции является наибольшим.
Я нашел различные вопросы и ответы / ссылки, обсуждающие, как сделать это с помощью NumPy, но это будет означать, что я должен превратить свои фреймы данных в NUMPY-массивы. И поскольку мои временные ряды часто охватывают разные периоды, я боюсь, что столкнусь с хаосом.
редактировать
Проблема, с которой я сталкиваюсь при использовании всех методов numpy/scipy, заключается в том, что им, похоже, не хватает понимания характера временных рядов моих данных. Когда я сопоставляю временной ряд, который начинается, скажем, в 1940 году, с тем, который начинается в 1970 году, панды corr
знает это, тогда как np.correlate
просто создает массив из 1020 записей (длина более длинной серии), заполненный nan.
Различные вопросы по этому вопросу указывают на то, что должен быть способ решить проблему различной длины, но до сих пор я не видел указаний на то, как использовать его для определенных периодов времени. Мне просто нужно сдвинуться на 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
И пытается скупиться
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 месяцев года, но я все еще предпочел бы встроенный метод.
2 ответа
Насколько я могу судить, нет встроенного метода, который бы выполнял именно то , что вы просите. Но если вы посмотрите на исходный код для метода серии Панды 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)]
Чтобы развить ответ Андре - если вы заботитесь только о (отстающих) корреляциях с целью, но хотите проверить различные лаги (например, чтобы увидеть, какое из них дает самые высокие корреляции), вы можете сделать что-то вроде этого:
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})
Таким образом, каждая строка соответствует разному значению задержки, а каждый столбец соответствует своей переменной (один из них является самой целью, дающей автокорреляцию).
Есть лучший подход: вы можете создать функцию, которая сместит ваш фрейм данных перед вызовом 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!!