python - columns - ¿Correlación cruzada(lapso de tiempo de correlación) con pandas?
pandas dataframe correlation between two columns (2)
Tengo varias series de tiempo, que quiero correlacionar, o mejor dicho, correlacionar entre ellas, para saber en qué momento el factor de correlación es mayor.
Encontré various questions y respuestas / enlaces sobre cómo hacerlo con numpy, pero eso significaría que tengo que convertir mis marcos de datos en matrices numpy. Y dado que mi serie de tiempo a menudo cubre diferentes períodos, me temo que me encontraré con el caos.
Editar
El problema que estoy teniendo con todos los métodos numpy / scipy, es que parece que no tienen conocimiento de la naturaleza temporal de mis datos. Cuando relaciono una serie de tiempo que comienza en, por ejemplo, 1940, con una que comienza en 1970, pandas corr
sabe, mientras que np.correlate
solo produce una np.correlate
1020 entradas (longitud de la serie más larga) llena de nan.
Las diversas Q sobre este tema indican que debería haber una manera de resolver el problema de la diferente longitud, pero hasta ahora, no he visto ninguna indicación sobre cómo usarlo para períodos de tiempo específicos. Solo necesito cambiar por 12 meses en incrementos de 1, para ver el tiempo de máxima correlación dentro de un año.
Edit2
Algunos datos de muestra mínimos:
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)
Debido a varios pasos de procesamiento, esos dfs terminaron cambiándose a df que se indexaron de 1940 a 2015. Esto debería reproducir esto
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)
Esto es lo que obtengo cuando me relaciono con pandas y cambio un conjunto de datos:
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
Y tratando de scipy:
In [456]: scicorr = scipy.signal.correlate(big1,big2,mode="full")
In [457]: scicorr
Out[457]:
array([[ nan],
[ nan],
[ nan],
...,
[ nan],
[ nan],
[ nan]])
que según whos
es
scicorr ndarray 1801x1: 1801 elems, type `float64`, 14408 bytes
Pero me gustaría tener 12 entradas. / Edit2
La idea que se me ha ocurrido es implementar una correlación de retardo de tiempo, así:
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
Pero esto probablemente sea lento, y probablemente estoy tratando de reinventar la rueda aquí. Editar El enfoque anterior parece funcionar, y lo he puesto en un bucle para pasar los 12 meses de un año, pero todavía preferiría un método incorporado.
Hay un mejor enfoque : puede crear una función que cambie su marco de datos antes de llamar al corr ().
Obtenga este marco de datos como un ejemplo:
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
Su función para cambiar otras columnas (excepto el objetivo):
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)
Suponiendo que su objetivo está comparando el prcp (variable de precipitación) con stp (presión atmosférica)
Si lo haces en el presente será:
>>> df.corr()
prcp stp
prcp 1.0 -0.2
stp -0.2 1.0
Pero si cambió 1 (una) período todas las demás columnas y mantiene el objetivo (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
Tenga en cuenta que ahora la columna stp se desplaza una posición hacia arriba en el período, por lo que si llama a corr (), será:
>>> df_new.corr()
prcp stp
prcp 1.0 1.0
stp 1.0 1.0
Así que, puedes hacerlo con lag -1, -2, -n !!
Por lo que puedo decir, no hay un método incorporado que haga exactamente lo que está preguntando. Pero si miras el código fuente del método autocorr
serie pandas, puedes ver que tienes la idea correcta:
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))
Así que una simple función de covarianza cruzada de tiempo sería
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))
Entonces, si quisiera ver las correlaciones cruzadas en cada mes, podría hacer
xcov_monthly = [crosscorr(datax, datay, lag=i) for i in range(12)]