Corrélation croisée (décalage-corrélation) avec pandas?
j'ai plusieurs séries chronologiques, que je veux corréler - ou plutôt, Cross-correlate - avec l'autre, pour savoir à quel décalage le facteur de corrélation est le plus grand.
j'ai trouvé divers questions et réponses/liens discutant comment le faire avec numpy, mais cela signifierait que je dois transformer mes images de données en tableaux numpy. Et puisque mes séries chronologiques couvrent souvent des périodes différentes, je crains que je sera exécuté dans le chaos.
Modifier
le problème que j'ai avec toutes les méthodes numpy/scipy, c'est qu'ils semblent manquer de conscience de la nature des séries temporelles de mes données. Quand je mets en corrélation une série chronologique qui commence par exemple en 1940 avec celle qui commence en 1970, pandas corr
le sait, alors que np.correlate
ne produit qu'un tableau 1020 entrées (longueur de la série plus longue) plein de nan.
les différents Q sur ce sujet indiquent qu'il devrait être un moyen de résoudre les différents longueur de problème, mais jusqu'à présent, je n'ai vu aucune indication sur la façon de l'utiliser pour des périodes de temps spécifiques. J'ai juste besoin de changer de 12 mois par incréments de 1, pour voir le temps de corrélation maximale dans un an.
Edit2
un minimum de données d'exemple:
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)
en raison de diverses étapes de traitement, ces FD se retrouvent changé en df qui sont indexés de 1940 à 2015. ceci devrait reproduire ceci:
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)
C'est ce que j'obtiens quand je suis en corrélation avec pandas et changer un ensemble de données:
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
Et en essayant de scipy:
In [456]: scicorr = scipy.signal.correlate(big1,big2,mode="full")
In [457]: scicorr
Out[457]:
array([[ nan],
[ nan],
[ nan],
...,
[ nan],
[ nan],
[ nan]])
qui, selon whos
est
scicorr ndarray 1801x1: 1801 elems, type `float64`, 14408 bytes
mais j'aimerais juste avoir 12 entrées. / Edit2
l'idée est venue avec, est de mettre en œuvre un décalage dans le temps de corrélation moi-même, comme suit:
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
mais c'est probablement lent, et j'essaie probablement de réinventer la roue ici. Modifier L'approche ci-dessus semble fonctionner, et je l'ai mis dans une boucle, de passer par tous les 12 mois de l'année, mais je préfère encore une méthode intégrée.
2 réponses
autant que je puisse dire, il n'y a pas de méthode intégrée qui fait exactement ce que vous demandez. Mais si vous regardez le code source pour la méthode de la série pandas autocorr
, vous pouvez voir que vous avez la bonne idée:
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))
ainsi une fonction de covariance croisée décalée dans le temps simple serait
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))
alors si vous vouliez regarder les corrélations croisées à chaque mois, vous pourriez faire
xcov_monthly = [crosscorr(datax, datay, lag=i) for i in range(12)]
il y a une meilleure approche : vous pouvez créer une fonction qui décalé votre dataframe d'abord avant d'appeler le corr().
Obtenez cette base de données comme un exemple:
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
votre fonction pour déplacer d'autres colonnes (sauf la cible):
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)
supposons que votre cible compare la prcp (variable de précipitation) avec stp(pression atmosphérique)
Si vous faites dans le présent:
>>> df.corr()
prcp stp
prcp 1.0 -0.2
stp -0.2 1.0
mais si vous décalé période 1(Un) toutes les autres colonnes et de garder le objectif (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
notez que maintenant la colonne stp est décaler une position vers le haut à la période, Donc si vous appelez le corr (), sera:
>>> df_new.corr()
prcp stp
prcp 1.0 1.0
stp 1.0 1.0
donc, vous pouvez faire avec lag -1, -2, - n!!